JVM运行时数据区域

根据 The Java® Virtual Machine Specification - Java SE 8 Edition,可以整理出其定义的JVM内存结构如下:


JVM Specification定义的运行时数据区域模型↑↑↑

其中,方法区所属的区域并没有强制要求。不同的JVM实现,其内存分布细节会不同。

1 PCR(程序计数寄存器 The Program Counter Register)

The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the $current method$ (§2.6) for that thread.

  • If that method is not native, the pc register contains the address of the Java Virtual Machine instruction currently being executed.
  • If the method currently being executed by the thread is native, the value of the Java Virtual Machine’s pc register is undefined. The Java Virtual Machine’s pc register is wide enough to hold a returnAddress or a native pointer on the specific platform.

2 JVM Stack

2.1 Frames 栈帧

A $frame$ is used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions.

A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). Frames are allocated from the Java Virtual Machine stack (§2.5.2) of the thread creating the frame. Each frame has its own array of local variables (§2.6.1), its own operand stack (§2.6.2), and a reference to the run- time constant pool (§2.5.5) of the class of the current method.
The sizes of the local variable array and the operand stack are determined at compile-time and are supplied along with the code for the method associated with the frame (§4.7.3). Thus the size of the frame data structure depends only on the implementation of the Java Virtual Machine, and the memory for these structures can be allocated simultaneously on method invocation.
Only one frame, the frame for the executing method, is active at any point in a given thread of control. This frame is referred to as the $current frame$, and its method is known as the $current method$. The class in which the current method is defined is the $current class$. Operations on local variables and the operand stack are typically with reference to the current frame.
A frame ceases to be current if its method invokes another method or if its method completes. When a method is invoked, a new frame is created and becomes current when control transfers to the new method. On method return, the current frame passes back the result of its method invocation, if any, to the previous frame. The current frame is then discarded as the previous frame becomes the current one.
Note that a frame created by a thread is local to that thread and cannot be referenced by any other thread.

2.1.1 Local Variables 本地变量表

A single local variable can hold a value of type

  • boolean,
  • byte,
  • char,
  • short,
  • int,
  • float,
  • reference
  • returnAddress.

A pair of local variables can hold a value of type long or double.

本地变量表通过索引来处理,第一个本地变量的下标(index)为0.

The Java Virtual Machine uses local variables to pass parameters on method invocation. On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.

Java虚拟机使用局部变量在方法调用上传递参数。 在类方法(静态方法)调用中,任何参数都是从局部变量0开始的连续局部变量中传递的。在实例方法调用中,局部变量0用于将引用(this)传递给调用者。 随后从局部变量1开始,连续的局部变量传递任何参数。

2.1.2 Operand Stacks 操作数栈

The maximum depth of the operand stack of a frame is determined at compile-time and is supplied along with the code for the method associated with the frame

用处:

The operand stack is empty when the frame that contains it is created. The Java Virtual Machine supplies instructions to load constants or values from local variables or fields onto the operand stack. Other Java Virtual Machine instructions take operands from the operand stack, operate on them, and push the result back onto the operand stack. The operand stack is also used to prepare parameters to be passed to methods and to receive method results.

2.1.3 Return Value

2.1.4 Dynamic Linking

Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support $dynamic linking$ of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.

JVM内部原理:

每个栈帧都包含了运行时常量池的引用。这个引用指向了这个栈帧正在执行的方法所在的类的常量池,它对动态链接提供了支持。

C/C++ 代码通常编译成一个对象文件,然后多个文件被链接起来生成一个可用的文件比如一个可执行文件或者动态链接库。在链接阶段,符号引用在每个对象文件里被替换成一个和最终执行相关的实际的内存地址。在Java里,这个链接过程在运行时是自动发生的。

当Java文件被编译时,所有的变量和方法引用都作为符号引用保存在class文件的常量池里。一个符号引用是一个逻辑引用并不是一个实际的指向一个物理内存地址的引用。不同的JVM实现能选择什么时候去解决符号引用,它通常发生在class文件加载后的验证,加载完成,立即调用或者静态解析等阶段,另外一种发生的时候是当符号引用第一次被使用,也叫做延迟或者延期解析。无论如何当每个引用第一次使用的时候,JVM必须保证解析发生,并抛出任何解析错误。绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次,因为符号引用是完全替换的。如果符号引用关联到某个类,而这个类却还没准备好,就会引发类加载。每个直接引用被保存为偏移地址而不是和变量或者方法在运行时的位置相关的存储结构。

3 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 storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated.

https://www.zhihu.com/question/49044988/answer/113961406 评论里:

如果“堆”是说Java heap,那么这个也对也错。因为JVM规范对抽象的“Java heap”的定义是“存储Java对象的地方”,也就是说Java对象在哪里,哪里就是Java heap。HotSpot的PermGen里是会存储部分Java对象的,例如说一些java.lang.String实例。这些String实例占的部分就得算是Java heap。

如果“堆”是说GC heap,那么这个错误。PermGen是HotSpot的GC heap的一部分

一般说“native memory”都是跟GC heap相对的,所以一般取上述后者的定义

4 Method Area

The Java® Virtual Machine Specification - Java SE 8 Edition:

The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads.

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.


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.

尽管方法区域在逻辑上是堆的一部分,但是简单的实现可以选择不垃圾收集或压缩它。 本规范不要求方法区域的位置或用于管理编译代码的策略


4.1 Run-Time Const 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.

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.

根据上面这段引用,可知以下几点:

  1. 每个类(或者interface,为便于行文,下面都统称为类)对应一个run-time constant pool
  2. 是class文件中constant_pool的运行时表达
  3. 在类被JVM加载时创建

那么,要理清其结构,需要先了解class文件的结构。可参见我的另一篇博文:Java class文件格式

其余具体的存储结构,JVM规范并没有作进一步阐述。

4.2 Field

具体的存储结构,JVM规范并没有作进一步阐述。

4.3 Method Data

具体的存储结构,JVM规范并没有作进一步阐述。

4.4 Code

具体的存储结构,JVM规范并没有作进一步阐述。

5 Native Method Stacks

Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.

Reference