运行时数据区域
程序计数器(Program Counter Register):可看作是当前程序所执行的字节码的行号指示器。在虚拟机的概念模型里(不同虚拟机可能有不同的实现方法),字节码解释器就是通过改变程序计数器的值来取下一条字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖于这个计数器。
Java虚拟机栈(Java Virtual Machine Stacks):与程序计数器一样,Java虚拟机栈也是线程私有的,他的它的生命周期和线程相同,虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
有人把Java内存分为堆(Heap)内存和栈(Stack)内存,而“栈”就是现在讲的虚拟机栈。局部变量表存放了相关局部变量,包括基本数据类型、对象引用和返回地址等。
虚拟机栈包括两种异常,StackOverflowError:所请求的栈深度大于虚拟机栈允许的最大深度。OutOfMemoryError:虚拟机栈扩展时无法申请到足够内存。
本地方法栈(Native Method Stacks):本地方法栈与虚拟机栈十分类似,不同之处在于虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机执行Native method服务,在有的虚拟机中直接将本地方法栈和虚拟机栈合二为一了。
Java堆(Heap):虚拟机管理内存中最大的一块,很多时候也被称为GC堆,Java堆被所有线程所共享,它在虚拟机启动时创建,用于存放对象实例。从内存回收角度看,该区又可细分为Eden空间、From Survivor空间和To Survivor空间,从内存分配角度看,该区可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。Java堆可以处于物理上不连续的内存空间中(逻辑上连续即可),目前主流的虚拟机的堆都是可扩展的(-Xms、-Xmx),若堆中内存不足以完成实例分配,也无法再扩展时,会抛出OutOfMemoryError异常。
方法区(Method Area):方法区也是各个线程所共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、编译器即时编译的代码等数据。方法区的内存回收目标主要针对常量池的回收和对类型的卸载,当方法区无法满足内存分配需求时,会抛出OutOfMemoryError异常。
运行时常量池(Runtime Constant Pool):运行时常量池是方法区的一部分,常量池(Constant Pool Table)用于存放编译期生成的各种字面量和符号引用,在类加载后进入方法区的运行时常量池中存放。
直接内存(Direct Memory):直接内存不是Java虚拟机定义的内存区域,在JDK1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道与缓冲区的IO方式,它可以使用Native函数库直接分配堆外内存,然后通过存储在Java堆中的DirectByBuffer对象引用这块内存,直接内存不受Java堆大小限制,只受本机总内存和处理器寻址空间的限制
参考资料:《深入理解Java虚拟机 JVM高级特性与最佳实践》