# 从Java虚拟机规范看HotSpot虚拟机的内存结构和变迁

## 引言

• HotSpot虚拟机中，Heap（堆），Method Area（方法区）和Run-Time Constant Pool（运行时常量池）的关系
• Method Area的在JDK1.6，JDK1.7和JDK1.8中的变迁（Perm Gen的消失和MetaSpace的出现）
• 字符串常量池的转移以及运行时常量池和intern方法的变化等。

## 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（堆）

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.

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 be chosen according to the implementor's system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.

• Heap是在Java虚拟机启动时创建的
• Heap中的对象占用的空间由自动存储管理系统所回收（其实就是GC）,对象不能被显式回收
• 自动存储管理系统（垃圾收集器）没有统一的实现，由虚拟机的实现者来选择
• Heap的空间大小可以是固定的，也可以进行扩充和收缩，Heap不需要连续的内存空间

### Method Area（方法区）

The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization

Method Area用于保存每个类的结构信息，如运行时常量池、字段和方法数据、以及方法和构造器的代码，包括用于类，对象和接口初始化的特殊方法

The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.

• Method Area是在Java虚拟机启动时创建的
• Method Area在逻辑上是Heap的一部分，但可以选择不对它进行垃圾收集
• Java虚拟机规范不强制规定Method Area的存储位置和管理已编译代码的策略
• Heap的空间大小可以是固定的，也可以进行扩充和收缩，Heap不需要连续的内存空间

### Run-Time Constant Pool（运行时常量池）

A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.

Run-Time Constant Pool的功能和传统编程语言的符号表类似，不过它包含的符号类型更广。

Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.

### 小结HotSpot VM的内存结构

• Heap用于为所有对象和数组分配内存
• Method Area用于保存类/接口的结构信息
• Run-Time Constant Pool用于保存各种常量

Method Area和Heap分开也是比较合理的，因为两者保存的数据类型不一样，数据的生命周期也不相同，分开存储更有利于管理和回收。

## HotSpot VM的内存模型变迁

### JDK1.7 数据向Java Heap和Native Heap迁移

• 字符串常量池（String Table）转移到了Java Heap
• 字面量（Interned Strings）转移到了Java Heap
• 类的静态变量（Class Statics）转移到了Java Heap
• 符号引用（Symbols）转移到了Native Heap

#### Java Heap和Native Heap有什么区别？

Native Heap是操作系统层面的堆区，是JVM进程运行时动态向操作系统申请的内存空间。JVM会在Native Heap中划出一块区域作为Java Heap(也有JVM Heap的说法，本文使用Oracle官网的名词)。Java Heap就是Java虚拟机规范里面的Heap。

### JDK1.8 MetaSpace成为Method Area的实现

• JDK 8 does not have Permanent Generation
• Class metadata is stored in a new space called Metaspace
• Not contiguous with the Java Heap
• Metaspace is allocated out of native memory
• Maximum space available to the Metaspace is the available system memory
• This can though be limited by MaxMetaspaceSize JVM option

## 字符串常量池和intern()方法

String Table在JDK1.6中位于Perm Gen，但是在JDK1.7中被转移到了Java Heap中，这次转移伴随着String.intern()方法的性质发生了一些微小的改变。

• 在1.6中，intern的处理是先判断字符串常量是否在字符串常量池中，如果存在直接返回该对象的引用。如果没有找到，则将该字符串常量加入到字符串常量区，也就是在永久代中创建该字符串对象，再把引用保存到字符串常量池中。
• 在1.7中，intern的处理是先判断字符串常量是否在字符串常量池中，如果存在直接返回该对象的引用，如果没有找到，说明该字符串常量在堆中，则处理是把堆区该对象的引用加入到字符串常量池中，以后别人拿到的是该字符串常量的引用，实际存在堆中。

## 结语

Java虚拟机规范是一份与实现无关的文档，它在描述时没有规定具体的实现细节，显得"模棱两可"，但所有的Java虚拟机实现都应该遵循这个规范。

## 参考资料

posted @ 2021-03-28 20:02  Yuchao_Huang  阅读(572)  评论(0编辑  收藏  举报