JVM体系主要包含以下部分:
类加载器、执行引擎,内存区,本地方法调用。
内存区一般即指运行时数据区,下面概括下各部分存储什么内容和作用:
程序计数器(PC寄存器):
线程私有。是一块较小的内存,可看作是线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。每个线程切换后能恢复到正确的执行位置,每条线程都有独立的程序计数器,各线程私有。入正在执行Java方法,记录正在执行的虚拟机字节码指令的地址;如果正执行Native方法,为空。没有规定任何OutOfMemoryError情况的区域。
Java虚拟机栈:
线程私有。描述Java方法执行的内存模型:每个方法在执行时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈到出栈的过程。就是我们常分的“堆”和“栈”中的栈,或者说是局部变量表部分。
局部变量表存放编译器可知的基本数据类型和引用类型。局部变量表所需内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈中分配多大的局部变量空间是完全确定的。
本地方法栈:
与虚拟机栈作用相似,不同的是虚拟机栈为执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。有的虚拟机入Sun Spot已将此部分与虚拟机栈合并。
Java堆:
线程共享。是Java虚拟机所管理的内存中最大的一块。在虚拟机启动时创建。唯一目的就是存放对象实例,几乎所有对象实例都在分配内存。是垃圾收集器管理的主要区域,亦成为“GC堆”。垃圾收集器基本都采用分代收集算法,所以,java堆还可以细分为:新生代和老年代;再细一点可分为Eden空间、From Survivor空间、To Survivor空间等。物理不连续,逻辑连续。可固定大小也可扩展。
方法区:
线程共享。存储一杯虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。JVM规范将其描述为堆的一个逻辑部分,但却有个别名——非堆,就是为与Java堆区分开来。
运行时常量池:
方法区的一部分,Class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项就是常量池,用于存放编译期生成的各种字面量和符号引用,这部分在类加载后进入方法区的运行时常量池中存放。
直接内存:
不属于是形式数据区一部分,也不是JVM规范中定义的区域。因为这部分内存被频繁使用,所以也要关注。在JDK1.4引入NIO类,引入了基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因此避免了在Java堆和Native堆中来回复制数据。