概述
不同于 C/C++ 程序,JVM 拥有自动内存管理机制,使得开发人员不需要手动地释放内存。但是对开发人员来说,还是应当了解 JVM 是如何使用内存的。
JVM 执行 Java 程序时,会根据 Java 虚拟机规范,将它所管理的内存分为几个区域,每个区域有各自的用途和功能。这些区域被称为运行时数据区域(Runtime Data Area)。其框图如下:

程序计数器(Program Counter Register)
程序计数器用于存储每个线程执行的 JVM 字节指令的位置。其工作方式类似于真实 CPU 中的 PC 寄存器。读取当前指令、分支、跳转等都依赖于程序计数器完成。
每一个线程都有独立的程序计数器,彼此互不干扰。因此,此数据区域是“线程私有”的。
另外,当运行 Native 方法时,则此数据区域中不存储信息。
JVM 栈(JVM Stack)

JVM 栈中用于存放当前线程中的一些数据:
1) 局部变量(基本类型)
Java 中定义的八种基本类型:boolean、char、byte、short、int、long、float、double。
除了 double 型数据占用两个 Slot(局部变量空间)外,其它数据在栈中占用一个 Slot。
2) 对象引用
对象的在堆中的地址或者可以得到对象的句柄。
3) returnAddress类型
指向一条字节码指令的地址。
4) 栈帧(Stack Frame)
栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法从调用到执行完成的过程,对应于一个栈帧在 JVM 栈中入栈到栈的过程。方法调用时,栈帧入栈;方法返回时,栈帧出栈。
与程序计数器类似,JVM 栈也是线程私有的,每个线程创建的同时都会创建各自的 JVM 栈。
此数据区域上定义了两种 Error:StackOverflowError 和 OutOfMemoryError。如果线程请求的栈深度超过 JVM 所允许的最大深度,将抛出 StackOverflowError;当 JVM 栈需要扩展,但无法申请到足够的内存时,将抛出 OutOfMemoryError。
堆(Heap)
堆是 JVM 用来存储对象实例以及数组值的区域,在虚拟机启动时创建,一般情况下,堆是 JVM 所管理的最大的一块内存区域。
Java 中所有通过 new 创建的对象的内存都在堆中分配,堆是 JVM 中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了 new 对象的开销是比较大的。
堆是 GC 工作的主要区域。
Heap中的对象的内存需要等待GC进行回收。由于 GC 基本都采用分代收集算法,所以堆中还可以细分为:新生代(Young)和老年代(Tenured)。还可以细分为:Eden, From, To 空间。
Sun Hotspot JVM 中,为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间 TLAB(Thread Local Allocation Buffer),其大小由 JVM 根据运行的情况计算而得,在 TLAB 上分配对象时不需要加锁,因此 JVM 在给线程的对象分配内存时会尽量的在 TLAB 上分配,在这种情况下 JVM 中分配对象内存的性能比较高,但如果对象过大的话则仍然是直接使用堆空间分配。
当堆无法获取足够的内存时,会抛出 OutOfMemoryError。对于 Hotspot JVM,可以通过参数 -Xms -Xmx 调整堆的大小。
方法区(Method Area)
方法区用于存放已被虚拟机所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为 final 类型的常量、类中的 Field 信息、类中的方法信息。当开发人员在程序中通过 Class 对象中的 getName、isInterface 等方法来获取信息时,这些数据都来自于方法区。
同时方法区域也是全局共享的,在一定的条件下它也会被 GC ,当方法区域需要使用的内存超过其允许的大小时,会抛出 OutOfMemoryError。对于 Hotspot JVM,可以通过 -XX:MaxPermSize 调整方法区大小的上限。
运行时常量池(Runtime Constant Pool)
存放的为类中的固定的常量信息、方法和 Field 的引用信息等,其空间从方法区域中分配。
本地方法栈(Native Method Stacks)
JVM 采用本地方法栈来支持 Native 方法的执行,此区域用于存储每个 Native 方法调用的状态。其与 JVM 栈的功能类似,同样的,也会抛出 StackOverflowError 和 OutOfMemoryError。
Reference
Jvm工作原理学习笔记 - OPEN 开发经验库. http://www.open-open.com/lib/view/open1408453806147.html
舒の随想日记 » 浅析Java虚拟机结构与机制. http://blog.hesey.net/2011/04/introduction-to-java-virtual-machine.html