JVM的内存管理
JVM在运行java程序的过程中,会使用到各种数据区,每个数据区都有自己的作用,创建和销毁的时间。JVM包括下面几个运行时数据区:
1.程序计数器(program counter Register)
每一个java线程都有一个程序计数器来用于保存程序执行到当先方法的哪个指令,对于非Native方法,这个区域记录的是正在执行的JVM原语的地址,如果正在执行的是 Native方法,这个区域则为空(undefined)。此内存区域是唯一一个在JVM.space中没有规定任何OutOfMemoryError情况的区域。
2.java虚拟机栈(java Virtual Machine stacks)
与程序计数器一样,JVM栈的生命周期与线程相同。JVM栈描述的是java方法调用的内存模型:每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表,操作栈,动态链接,方法出入口信息等。每个方法的调用至完成,就意味着一个帧在JVM栈中的入栈至出栈的过程。
本地变量表存放了编译期可知的各种标量类型(boolean, byte, char, short,int,float,long,double),对象引用(不是对象本身,仅仅是一个引用指针),方法返回地址 等。其中long和double会占用2个本地变量空间(32bit),其余占1个。本地变量表在进入方法时进行分配,当进入一个方法时,这个方法需要在帧中分配多大的本地变量是 一件 完全正确的事情,在方法运行期间不会改变变量表大小。
在JVM.Space中对这个区域规定了2种异常情况,如果线程请求的栈的深度大于虚拟机所允许的深度,将会抛出StackOverflowError异常,如果JVM栈可以动态扩张,当扩展 时无法申请到足够内存时,将会抛出OutOfMemoryError异常。
3.本地方法栈(Native method stacks)
本地方法栈与JVM栈的作用是类似的,只不过JVM栈是为虚拟机运行JVM原语服务,而本地方法栈是为虚拟机使用到的Native方法服务,它的实现语言,方式与结构并没有做强制规定,甚至有的虚拟机将JVM栈与本地方法栈合二为一。本地方法栈也会抛出StackOverflowError和OutOfMemoryError。
4.Java堆(java heap)
对于绝大多数的应用来说,java堆是虚拟机管理的最大的一块内存,java堆被所有的线程共享,在虚拟机启动时创建,Java堆的唯一目的就是存放对象实例,绝大部分的对象实例都是在这里分配的。
Java堆可以处于物理上不连续的内存空间,它逻辑是连续的就可以了,可以固定大小,也可以可扩展,如果堆中无法分配内存,并且堆也不能扩展的时候就报OutOfMemoryError。
5.方法区(method area)
方法区也叫永久代(permanent generation),它还有要给别名Non-heap(非堆),在JVM.Space中描述该区为堆的一个逻辑部分。方法区中存放每个class的结构信息,包括常量池,字段描述,方法描述等,