Java运行时数据区域

运行时数据区域
Java虚拟机在执行Java程序的过程当中会把它管理的内存划分为若干个不一样的数据区域。这些区域都有各自的用途,以及建立和销毁的时间,有的区域随着虚拟机进程的启动而存在, 有些区域则是依赖用户线程的启动和结束而创建和销毁。如图
1.1 程序计数器
是一块内存比较小的空间。做用:用来标志当前线程所执行的字节码的行号指示器(即在字节码中添加编号)。在jvm中,字节码解释器工做时就是经过改变这个计数器上的值来选取下一条须要执行的字节码指令。在分支、循环、跳转、异常处理、线程恢复等功能都须要依赖计数器去完成。在多线程中, 各条线程之间的计数器互不影响,独立存储。
不会存在OutOfMemoryError状况的区域。
1.2 Java虚拟机栈
Java虚拟机栈也是线程私有的, 生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每一个方法被执行的时候都会建立一个栈帧用于存储局部变量表、操做数栈、动态链接、方法出口等,而且每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
先理解什么是栈帧:是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧是基于虚拟机栈上的,一个虚拟机栈存储了多个栈帧,每一个栈帧记录Java方法中局部标量表、操做数栈等信息同时也记录该方法从入栈到出栈的过程。存储结构如图
在编译程序代码的时候,栈帧中须要多大的局部变量表,多深的操做数栈都已经彻底肯定,而且写入到方法表的Code属性之中,所以一个栈帧须要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。
局部变量表: 是一组变量值的存储空间,用于存放方法参数、局部变量和对象引用类型。在编译程序代码后就肯定须要局部变量的最大容量。变量槽是局部变量表中的最小单位。一个solt能够存放(x32)boolean、byte、char、short、int、float、reference 和 returnAddress(执行字节码指令的地址);对于64位的long和double变量则须要分配两个连续的slot空间。为了节省栈空间Slot是能够重用的。不过有时也会影响垃圾回收行为。
图一
图二
从图一和图二中能够看出,图二中变量槽是能够重用的,变量a复用了placeholder的slot,致使placheholder的引用被删除,内存被回收。
操做数栈常称为操做栈是一个后入先出栈。其最大的栈深度也在编译过程当中就肯定了并保存在Class文件的Code属性中。应用场景:在方法进行参数传递的时候是经过操做数栈进行的。 在概念模型中,两个栈帧做为虚拟机栈的元素, 相互之间是彻底独立的, 可是大多数虚拟机的实现里都会作些优化处理,使得两个栈帧出现一部分重叠。让下栈帧的部分操做与上面栈帧的部分局部变量表重叠在一块儿,这样在进行方法调用返回时就能够共用一分部数据,而无需进行额外的参数复制传递了。
动态链接:每一个栈帧都包含一个执行运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程当中的动态链接。Class文件中存放了大量的符号引用,字节码中的方法调用执行就是以常量池中指向方法的符号引用做为参数。这些符号引用一部分会在类加载阶段或第一次使用时转化为直接引用,这种转化称为静态解析。另外一部分将在每一次运行期间转化为直接引用,这部分称为动态链接。
方法出口:方法出口分为两种, 一种收到返回命令,正常退出;第二种执行遇到异常致使方法退出。
  
虚拟机栈会出现两种异常:StackOverflowError和OutOfMemoryError
1.3 本地方法栈
本地方法栈与虚拟机栈做用很是类似,其区别不过是虚拟机栈为执行Java方法(字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
Native方法:并不必定指Java中用native方法(如String.intern() :native方法),也包括其余库或者其余语言中的方法如C、C++。
本地方法栈也会出现两种异常:StackOverflowError和OutOfMemoryError
1.4 Java堆
Java堆是Java虚拟机所管理的内存中最大的一块。是被全部线程共享的一块内存区域,虚拟机启动时建立。此内存区域的惟一目的就是存放对象实例。几乎全部的对象实例都在这里分配内存,但随着jit编译器的发展会有微妙的变化。
Java heap 是垃圾收集器管理的主要区域。在Java中,堆被划分红两个不一样的区域:新生代(Young)和老年代(Old)。新生代又被划分为三个区域:Eden空间、From Survivor空间、To Survivor空间。这样划分的目的是为了更好地管理内存中的对象,包括内存的分配以及回收。堆的内存模型如图(jdk1.6)
从图中能够看出:堆大小=新生代+老年代。其中堆大小能够经过参数-Xms、-Xmx来设置。
Java 堆会有OutOfMemoryError异常
1.5 方法区
方法区与Java堆同样,是各个线程共享的内存区域,可是存储的内容不一样。方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。别名Non-Heap. 另外方法区并非连续的,因此垃圾收集行为在这个区域是不多出现的。
方法区还包括一部分:常量池。常量池是用于存放编译器生成的各类字面量和符号引用,这部份内容将在类加载后存放到方法区的运行时常量池中。大小能够经过-XX:PermSize和-XX:MaxPermSize设置。
方法区会有OutOfMemoryError异常
总结:
一、区分下java栈、java堆和方法区分别存储内容:
public class Demo{
private String name ;
public Demo(String name){
this.name = name;
}
public static void main(String[] args){
Demo d = new Demo("test");
}
}
java堆          方法区         java栈
new Demo()     Demo类信息    Demo d、局部变量name
    Demo中的方法名   调用main方法主线程调用栈
相关文章
相关标签/搜索