一:JVM学习一JVM内存模型

之前本身只是用java去编写程序,没有深刻了解过,空闲下来本身看看书,学习JVM相关知识,这也是自我深造学习。虽然如今网上有不少这方面的博文之类,可是我认为我还有必要本身去整理写一下,毕竟看得多不如本身多动手亲自去写一遍。html

JAVA程序的之因此可以实现一次编译到处运行,得益于他强大的虚拟机,虚拟机会将编译好的字节码文件加载到虚拟机内存中,通过一系列的验证以后,初始化,最后在卸载加载的class文件。平常咱们用的最多的就是Sun公司的HotSpot虚拟机,此外还有BEA 的JRockit虚拟机和IBM的J9虚拟机。java

闲话很少说,下面图表是一个java虚拟机运行时数据区,图片的来源于http://www.cnblogs.com/AloneSword/p/4262255.html算法

由图表能够看出方法去和堆区是虚拟机中线程共享的,虚拟机栈和本地方法区以及程序计数器是线程私有的。编程

程序计数器:数组

    是一块较小的内存空间,它的做用能够看作是当前线程所执行本身吗的行号指示器,在虚拟机的概念模型李,字节码解释器工做时就是经过改变这个计数器的值来选取下一条须要执行的字节码指令,分支,循环,跳转、异常处理、县城恢复等基础功能都须要依赖这个计数器去完成。
多线程

    因为Java虚拟机的多线程是经过线程轮流切换并分配处理器执行时间的方式实现,在任何一个肯定的时刻,一个处理器(对于多核处理器来讲是一个内核)只会执行一条线程中的指令。所以,为了线程都须要一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,所以咱们把这类内存区域称为“线程私有”的内存区域。
编程语言

    若线程正在执行一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,若是执行的native方法简单地讲,一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,好比C。这个特征并不是java所特有,不少其它的编程语言都有这一机制,好比在C++中,你能够用extern "C"告知C++编译器去调用一个C的函数。),这个计数器的值就为空,这块区域是惟一一个在java虚拟机规范中没有规定任何OutOfMemoryError的区域。
函数

JAVA虚拟机栈:学习

    和程序计数器同样,java虚拟机栈也是线程私有的。它的生命周期和线程相同。虚拟机栈中描述的是java方法执行的内存模型:每一个方法在执行的时候都会同时建立一个栈帧用于存储局部变量表、操做数栈、动态连接、方法出口等信息,每个方法被调用到执行完成工程就对应这个一个栈帧在java虚拟机栈中从入栈道出栈的过程。
编码

    局部变量表:

            局部变量表是一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。改空间的大小通常在java程序被编译为class文件的时候就会被肯定下来。

    操做数栈:

            顾名思义,他就是java程序在执行方法时候的一个操做数据的栈,是一个后入先出栈。同局部变量表内存空间大小同样,该部分容量在编译的时候已经肯定。操做栈中的每个元素能够是任意的java数据类型,32位数据占用的栈容量为1,64位数据占用的栈空间容量为2.

            当方法刚开始执行的时候,这个方法的操做数栈内是空的,在方法执行过程当中会有各类字节码指令向操做数栈中写入和提取内容,也是就入栈和出栈操做,例如在作数学运算就是经过操做数栈来进行的。

      动态连接方法:

            每一个栈帧中包含一个指向运行时常量池中该栈帧所属方法的引用(运行时常量池是方法区中的一部分),持有该引用是为了支持方法调用过程当中的动态连接。class文件中的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数,这些符号引用一部分会在类加载阶段或者第一次使用的时候转化为直接引用,另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

    返回地址:

        当一个方法在执行后,有两种方式退出方法,一种是执行引擎遇到任意一个方法返回的字节码指令,这种方法的退出方式为正常退出,另外一种是在执行过程当中遇到异常退出。可是不管采用哪一种方式退出,在方法退出以后,都须要返回到方法被调用的位置,程序才能继续执行,方法返回的时候须要在栈帧中保存一些信息,用来帮助恢复他的上层方法的执行状态。

本地方法栈:

    本地方法栈和虚拟机栈发挥的做用相似,区别就是虚拟机栈执行java方法也就是字节码服务,而本地方法栈执行的虚拟机用到Native方法服务。改区域也是线程私有的。

因为sun公司的HotSpot虚拟机直接把本地方法栈和虚拟栈合二为一,因此在设置该区域大小的时候能够经过-Xss参数进行设置,该区域会抛出StackOverflowError和OutOfMemoryError异常。

JAVA堆:

    该区域是java虚拟机管理的内存中最大的一块,java堆是被全部线程共享的一块内存区域,在虚拟机启用时建立,该区域的惟一目的就是存放对象的实例,几乎全部的对象实例都在这里分配,这一点在java虚拟机规范中的描述是:全部的对象实例以及数组都要在该区域进行分配空间。

    改取用能够经过参数-Xms和-Xmx进行设置大小。

    java堆是进行垃圾收集器管理的主要区域,所以不少时候被称为GC堆,因为如今收集器基本采用的分代收集算法,所以java堆中还能够细分为新生代和老年代,新生代再细致一点就是Eden空间,From Survivor空间和To Survivor空间,他们的分配比例通常是8:1:1,。该区域会抛出OutOfMemoryError异常。

方法区:

        和java堆同样,是线程共享的内存区域,它主要用于存放已被虚拟机加载的类信息,常量、静态变量、即时编译器编译后的代码等数据。虽然JAVA虚拟机规范把方法区描述为堆的一个逻辑部分,可是它却又一个别名非堆(Non-Heap)。

    运行时常量池:

        该区域也是方法区的一部分,它主要指的是在编译期被肯定,并被保存在已编译的class文件中的一些数据。除了包含类中定义的一些基本数据(int,long)和对象型(String,Integer)的常量值,还包含一些以文本形式出现的符号引用,好比1:类和接口的限定名,2:字段的名称和描述符,3:方法的名称和描述符。

    虚拟机必须为每一个装载的类型维护一个常量池。常量池就是该类型用到的一个常量的有序集合,包括直接常量和其余类型,字段,方法和符号引用。对于String常量,她的值存储在常量池中,而JVM的常量池在内存中是以表的形式存在的,对于String类型,有一个固定长度的CONSTANT_String_info表存储字符串的值。

    常量池中的项目类型:CONSTANT_Utf8_info 标志1,表明的是UTF-8编码的额字符串;CONSTANT_Integer_info,标志3,整型字面量;CONSTATN_Float_info,标志4,浮点型字面量;

CONSTANT_Long_info,标志5,表明Long类型的字面量;CONSTANT_Double_info,标志6,表明双精度浮点型字面量;CONSTANT_Class_info,标志7,表明类和接口的符号引用;CONSTANT_String_info,标志8,表明字符串类型字面量;CONSTANT_Fielderf_info,标志9,表明字段的符号引用;CONSTANT_Methodref_info,标志10,表明勒种方法的符号引用;CONSTANT_InterfaceMethodref_info,标志11,表明接口中方法的符号引用;CONSTANT_NameAndType_info标志12,表明字段或方法的部分符号引用。

        对于在HotSpot虚拟机上开发和部署的程序开发者而言,不少人愿意把它称为永久代(Permanent Generation),可是二者并不等价,仅仅是由于HotSpot虚拟机设计团队选择把Gc分代收集扩展到方法区。

        该区域除了和java堆同样不须要选择连续的内存和能够选择固定大小或者可扩展外,还能够选择不实现垃圾收集。相对而言,垃圾收集行为在该区域比较少,可是并不是数据进入该区域就会“永久”存在,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载。

    根据java虚拟机规范,当方法区没法知足内存分配需求的时候,将会抛出OutOfMemoryError异常。

相关文章
相关标签/搜索