引言
网上有大量讨论JVM的内存模型的文章,但很多内容都是到处摘抄而来,导致许多概念模糊不清。
比如对于“JVM内存模型”和“Java内存模型(JMM)”没有区分,实际上,Java内存模型(JMM)是一种规范,和具体的Java虚拟机的内存结构不是一个概念,不应该把诸如“年轻代“、”老年代”这类关于虚拟机具体实现的讨论归为Java内存模型。
而在具体讨论JVM的内存结构时,还应该指出,我们通常讨论的都是HotSpot虚拟机中的实现,这些模型并不是所有虚拟机通用的,比如“Perm Gen(永久代)”就是HotSpot中的概念,JRockit中并没有永久代。
此外,不应该把“永久代”和“方法区”混为一谈,永久代(Perm Gen)只是HotSpot对于Java虚拟机规范中方法区(Method Area)的一种实现,后来被改成了元空间(MetaSpace),文中会具体介绍这些变化。
本文希望从Java虚拟机规范出发,尽可能通过查阅官方文档,以及阅读HotSpot VM中的部分核心源代码的方式,重新梳理Java虚拟机的内存结构,重点讨论:
- HotSpot虚拟机中,Heap(堆),Method Area(方法区)和Run-Time Constant Pool(运行时常量池)的关系
- Method Area的在JDK1.6,JDK1.7和JDK1.8中的变迁(Perm Gen的消失和MetaSpace的出现)
- 字符串常量池的转移以及运行时常量池和intern方法的变化等。
而Jvm中的The pc Register
、Java Virtual Machine Stacks
和Native Method Stacks
这些部分,则不在本文的讨论范围之内。
Java虚拟机规范中的内存模型
Java虚拟机规范上指定了Java虚拟机的运行时数据区包括The pc
Register、Java Virtual Machine Stacks、 Heap、 Method Area、Run-Time Constant Pool和Native Method Stacks这些部分,其中PC寄存器,Java虚拟机栈和本地方法栈会为每个线程所创建,属于线程私有,而堆,方法区和运行时常量池是所有线程共享的。
PC寄存器,Java虚拟机栈和本地方法栈的作用与传统的操作系统类似,这里不多赘述,我们主要关注Heap(堆),Method Area(方法区)和Run-Time Constant Pool(运行时常量池)的规范。
Heap(堆)
首先查看Java虚拟机中对Heap的定义:
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
上面的定义指出,Heap是Java虚拟机中为所有Java虚拟机线程所共享的内存区域,它是一块为所有对象和数组分配内存的运行时数据区。
规范中还有下面的一段描述:
The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may b