本文是《The Java Virtual Machine Specification (Java SE 7 Edition)》2011年6月版的运行时数据区的翻译
原文参见:http://download.oracle.com/javase/7/specs/jvms/JVMS-JavaSE7.pdf 译者:方腾飞
JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创建,在JVM退出的时候销毁。而其他的数据依赖于每一个线程,在线程创建时创建,在线程退出时销毁。
2.5.1 程序计数器(The pc Register)
JVM一次能支持很多线程执行。每一个JVM线程有它自己的程序计数器。在任何时候,一个JVM的线程都正在执行当前线程的方法代码。如果这个方法不是本地方法,程序计数器包含当前被执行的JVM地址。如果线程正在执行本地方法,程序计数器的值为未定义。JVM 程序计数器足以存储一个返回地址或一个本地指针。
2.5.2 栈(Java Virtual Machine Stacks)
每个JVM的线程在创建的时候,都会创建一个栈。一个栈包含很多栈桢。JVM的栈好比传统语言C的栈,它维持(存储)本地变量和部分结果,并在方法调用和返回中(被)使用。由于JVM栈除了压入和弹出栈帧之外不能被直接操作,栈帧可以在堆上分配空间。 JVM说明书(规范)允许栈要么是一个固定大小,要么动态扩展来满足计算的要求。如果JVM栈是一个固定的大小,当栈被创建的时候每一个栈大小可以自由设置。 在动态扩展情况下,可以控制最大最小内存。 在VM Spec中对这个区域规定了2种异常状况(以下两种异常与JVM的栈机制有关):
- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
- 如果VM栈可以动态扩展,在初始化新线程时没有足够内存创建栈则抛出OutOfMemoryError异常。
2.5.3 堆(Heap)
JVM有一个在所有线程内共享的堆。堆是给所有类的实例和数组分配内存的运行时数据区。 堆在虚拟机启动的时候创建,堆中储存的对象通过一个自动存储管理系统(垃圾回收器)进行回收。 对象从不明确的被分配(JVM从不指明对象的释放)。JVM加上没有(JVM不指定特定的自动存储管理系统)自动存储管理系统的特别的类型,(开发者可根据系统要求自主选择)并且这个存储管理技术可能被选择按照实现的系统需求。
堆要么是固定大小,要么按计算需要扩展。如果一个大的堆变得多余或许会收缩。堆的内存不需要相邻。使用者可以设置堆内存的大小,如果堆能够动态的扩展。控制最大最小堆内存。
堆会出现以下异常:
- 如果内存溢出(若计算所需堆内存不足),则抛出OutOfMemoryError
2.5.4 方法区(Method Area)
JVM的方法区是所有线程共享的,方法区类似于传统语言编译代码时的存储区域或类似于操作系统进程的文本段。他存储内容包括:每一个类的结构,如运行时常量池,字段和方法的数据;方法和构造器的代码,如用于类,实例和接口初始化的特殊方法。这个方法区在JVM启动的时候被创建,一般情况下JVM不会选择对方法区进行垃圾回收或者压缩,这个版本的JVM规范没有强制规定方法区的位置和管理编译后代码的策略。方法区可固定大小,或按需伸缩。方法区的内存不需要相邻。
2.5.4 运行时常量池(Runtime Constant Pool)
运行时常量池是类和接口运行时的常量池表,它在字节码文件里。它包含几类常量。 在编译时期识别的数值常量,在运行区识别的方法或引用字段。运行区常量池类似于传统语言的字符表,但它比传统字符表所存储的范围更广。每一个运行区常量池从方法区分配内存。当类和接口被JVM创建时相应的常量池也被创建。
运行区常量池包括以下异常:
- 当类和接口创建时,如果运行区常量池所需内存不足,则抛出OutOfMemoryError。
2.5.5 本地方法栈(Native Method Stacks)
JVM一般用传统栈实现,俗称“C栈”用来支持本地方法(这些方法不是用java编程语言写的方法)。本地方法栈还可以被用于翻译C语言所编写的JVM指令集。那些不加载本地方法,不依赖于传统栈所实现的JVM不需要提供本地方法栈。如果提供本地方法栈,每个线程创建时必须分配一个本地方法栈。JVM规范规定本地方法栈可固定长度或按需伸缩。 如果JVM栈是一个固定的大小,当栈被创建的时候每一个栈大小可以自由设置。 在动态扩展情况下,可以控制最大最小内存。
JVM的方法栈有以下两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
- 如果VM栈可以动态扩展,当扩展时无法申请到足够内存(或者在初始化新线程时没有足够内存创建栈)则抛出OutOfMemoryError异常。