引言
Java 虚拟机(Virtual Machine)在执行 Java 程序时, 会将它所管理的内存划分为不同的数据区,这些分块有不同的功能,理解它们各自的特点,对于深入理解java程序运行机制和调优Java代码,具有重要意义。其实个人觉得,理解 Java 虚拟机的原理,也没想象中的复杂(也许我的想法有点天真啊^_^),它的运行机制,就像一个小型操作系统,这也许就是虚拟机的来源吧。
Java VM运行时数据区结构图
运行时数据区域解释
本地方法栈
该区域所发挥的作用与虚拟机栈类似,只不过它是为执行 Native 方法服务,而虚拟机栈为执行 Java 方法(即字节码)服务的,见下文的解释。
虚拟机栈
描述 Java 方法执行的内存模型,每个方法执行时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法返回地址等信息。
若线程请求栈的深度超过 VM 所规定的最大深度,将抛出 StackOverflowError异常。若内存动态扩展时申请内存失败,将抛出 OutOfMemoryError异常。
程序计数器
类似于计算机体系结构中的 PC(Program Counter,也叫程序计数器),作用也非常相似,就是指示当前线程所执行的字节码指令。分支、循环、跳转、异常处理、线程恢复等都需要它来完成。
若当前线程正在执行 Java 的方法,则程序计数器的值记录的是正在执行的虚拟机字节码指令;若执行的是 Native 方法,则值为空(Undefined)。
此内存区域为 唯一在Java VM 规范文档中没有规定任何 OutOfMemoryError情况的内存区域。
堆
是VM所管理的内存中最大的一块区域,被所有线程共享,在VM启动时创建,几乎所有的对象实例都在该区域分配内存。该区域的内存在逻辑上是连续的,但在物理上不一定是连续的内存空间。(怎么看都怎么像操作系统的内存管理机制啊,呵呵。)
方法区
用于存储已被VM加载的类信息、常量、静态变量、即时编译器编译后的代码、运行时常量池等数据。
总结
仔细观察 Java 虚拟机各模块的作用,再对比操作系统的内存分配原理和机制,发现二者非常相似,这也是“大道三千,殊途同归”的诠释啊!