Java虚拟机内存主要包括程序计数器,虚拟机栈,本地方法栈,方法区,堆,如下图
下面针对每个数据区存储的内容以及作用分别进行说明
程序计数器
这个是线程私有的区域,即每个线程都有自己的程序计数器。是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令(当然,实际的虚拟机会采取更加高效的方式去实现)
如果线程执行的是java方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是Native方法,这个计数器为空(Undefined)
Java虚拟机栈(线程私有)
生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
在我们通常所说的堆内存(Heap)、栈内存(Stack)。其中栈内存往往表示的就是这里的虚拟机栈或者说是虚拟机栈中的局部变量表部分。
局部变量表存放了编译期可知的各种基本类型(boolean,byte,char,short,int,float,long,double)、对象引用以及returnAddress类型(指向了一条字节码指令的地址)
本地方法栈(线程私有)
本地方法栈与虚拟机栈的区别是,本地方法栈为虚拟机使用的Native方法服务,而虚拟机栈为虚拟机执行Java方法服务,在Sun HotSpot虚拟机中是直接将本地方法栈与虚拟机栈合二为一的。
Java堆(线程共享)
用于存放对象实例,几乎所有的对象实例都是在这里分配内存。而Java堆也是垃圾回收器管理的主要区域。
由于现在的收集器基本上采用分代收集算法,所以Java堆中还可以细分为:新生代和老生代。如果从内存分配的角度来看,Java堆中可能划分出多个线程私有的分配缓冲区(TLAB)。
参数-Xmx和-Xms分别控制堆的最大内存和最小内存。
方法区(线程共享)
用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
此区域的内存回收目标主要是针对常量池的回收和对类型的卸载。其中类型的卸载的条件 相当苛刻。
运行时常量池(方法区的一部分)
此区域是方法区的一部分,在Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。