根据《java虚拟机规范(java SE 7 版)》的规定,java虚拟机在执行java程序时会把它所管理的内存区域划分为5个不同的数据区域:程序计数器、java虚拟机栈、本地方法栈、java堆、方法区,下图为java虚拟机运行时的计算机内存划分图:
java虚拟机运行时管理的内存区域:java虚拟机在运行时可以分配的内存区域,不包括java虚拟机执行引擎本身占用的内存空间。打个比方,如果把机器内存比作一间房子,那么java虚拟机就像是房子中的一只箱子,箱子中的空间就是java虚拟机在运行时可以分配的内存区域,但是箱子有厚度,因此本身也是占据空间的,只不过占据的是整个房子的空间而已。
程序计数器(Program Counter Register):线程私有,每一个线程都会有一个独立的程序计数器,相互之间无干扰。它是一块较小的内存区域,是当前线程所执行的字节码指令的行号指示器。这与CPU控制器中的程序计数器的概念有些相似。只不过java虚拟机的程序计数器位于机器内存中,而CPU的程序计数器位于CPU控制器内部。两者的作用都是为了指出接下来要执行的是哪一条指令。该内存区域不会抛出OutOfMemoryError的异常。
虚拟机栈(Virtual Machine Stack):线程私有,生命周期与线程相同。虚拟机栈用于存放java方法的栈帧,这是一种用于支持虚拟机进行方法调用和方法执行的数据结构,包含方法的局部变量表、操作数栈、动态链接、方法出口等信息。方法的调用伴随着栈帧的入栈,方法的退出伴随着对应栈帧的出栈。当前正在执行的语句所属的方法的栈帧总是在虚拟机栈顶,当虚拟机栈中的栈帧数为0时,意味着当前线程的结束。如果虚拟机栈中的栈帧数目过多,以至于超过了虚拟机栈所允许的深度,将会抛出StackOverflowError(栈溢出错误)的异常。当前大多数虚拟机栈都是可扩展的,但如果扩展时无法申请到足够内存,则会抛出OutOfMemoryError。关于StackOverflowError和OutOfMemoryError的将会在后续笔记中进行深入分析。
本地方法栈(Native Method Stack):线程私有,与虚拟机栈的作用非常相似。本地方法栈服务于Native方法。本地方法栈可以被虚拟机自由实现,甚至当下主流的java虚拟机HotSpot直接将本地方法栈和虚拟机栈进行了合并。
堆(Heap):线程共享,即任何同一个java虚拟机实例中的任意线程都可以使用该内存区域。是java虚拟机所管理的内存区域中面积最大的一块。在虚拟机启动时创建。作用是存放对象实例。绝大多数对象实例都在此分配内存,而对象实例的引用则存放于栈中。堆是垃圾收集器管理的主要区域,因此该区域通常也被称为GC堆(Garbage Collected Heap)。从垃圾回收角度来看,由于现在收集器基本上都采用分代收集算法,因此java堆还可以细分为:新生代和老年代。堆在物理上可以是间断的内存空间,就像磁盘上的文件存储可能是以磁盘碎片的形式进行存放,但只要在逻辑上是连续的即可。例如,java虚拟机在32位内存上的占用区域为:0x3000~0x3100、0x3200~0x3300,显然,该内存区域是间断的,但对于java虚拟机而言,只要在访问内存的时候认为0x3100的下一个内存地址是0x3200,即逻辑上的连续即可。堆可以设置为固定大小或者可扩展。堆也有可能抛出OutOfMemoryError异常。
方法区(Method Area):线程共享,存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。与堆一样,物理上可间断,逻辑上连续。也可以设置为固定大小或者可扩展。这一片区域的垃圾回收行为较少,主要针对运行时常量池进行垃圾回收。方法区也有可能抛出OutOfMemoryError异常。
运行时常量池(Runtime Constant Pool):线程共享,是方法区的一部分(实际上,HotSpot虚拟机在JDK7和JDK8中并非如此划分,这一点会在后续笔记中提到)。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将会在类加载后进入方法区的运行时常量池。运行时常量池具有动态性,及非编译期的常量也能进入常量池中,例如String的intern()方法会将字符串常量池中不存在的字符串放进常量池(存在则直接返回字符串引用地址)。同样,运行时常量池也有可能抛出OutOfMemoryError异常。
直接内存(Direct Memory):直接内存不属于java虚拟机管理的内存区域。java虚拟机可以通过关键字native声明的接口(Java Native Interface)来访问本地动态链接库中的方法,从而通过java程序调用非java程序,这一点在实际生产中用的很多。同样,对该区域的访问也有可能抛出OutOfMemoryError异常。