JVM 的运行时数据区

JVM(Java Virtual Machine)的运行时数据区(Runtime Data Areas)是指在JVM运行过程中,用于管理和存储程序数据的内存区域。这些内存区域在JVM启动时分配,并在JVM关闭时释放。根据《Java虚拟机规范》,运行时数据区可以划分为以下几个部分:

1. 程序计数器(Program Counter Register)

程序计数器是一个小内存区域,每个线程都有自己的程序计数器。它用于存储当前正在执行的字节码指令的地址。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的字节码指令的地址;如果正在执行的是本地方法(native method),这个计数器值则为空(Undefined)。

2. Java虚拟机栈(Java Virtual Machine Stack)

Java虚拟机栈是线程私有的,每个线程都有一个自己的Java虚拟机栈。它存储着线程的状态信息,包括方法调用和执行的相关数据。每个方法被调用时,都会在Java虚拟机栈中创建一个栈帧(Stack Frame),用于存储局部变量、操作数栈、动态链接、方法出口等信息。当方法执行完毕,栈帧会被销毁。

栈帧(Stack Frame)

每个栈帧包括:

  • 局部变量表(Local Variable Table):存储方法的局部变量,包括基本数据类型、对象引用和returnAddress类型。
  • 操作数栈(Operand Stack):用于存储计算过程中的中间结果,并作为方法调用和返回时的参数传递。
  • 动态链接(Dynamic Linking):每个栈帧包含一个指向运行时常量池的方法引用,支持当前方法的动态链接。
  • 方法返回地址(Return Address):当方法调用完成后,需要返回到调用方法的位置。

3. 本地方法栈(Native Method Stack)

本地方法栈与Java虚拟机栈类似,但它是为本地方法服务的。每当一个本地方法被调用时,就会在本地方法栈中创建一个栈帧。它主要用于处理通过JNI(Java Native Interface)调用的C/C++代码。

4. 堆(Heap)

堆是JVM内存中最大的一块区域,所有的对象实例和数组都在堆中分配内存。堆是所有线程共享的内存区域。根据垃圾回收机制的需要,堆可以进一步细分为新生代(Young Generation)和老年代(Old Generation)。

新生代(Young Generation)

新生代存储生命周期较短的对象。新生代又分为三个区域:

  • 伊甸区(Eden Space):新创建的对象首先分配在伊甸区。
  • 幸存者区0(Survivor Space 0):从伊甸区复制过来的存活对象。
  • 幸存者区1(Survivor Space 1):从幸存者区0复制过来的存活对象。

老年代(Old Generation)

老年代存储生命周期较长的对象。当对象在新生代经过多次垃圾回收仍然存活时,会被移动到老年代。

5. 方法区(Method Area)

方法区是一个共享内存区域,用于存储已被JVM加载的类信息、常量、静态变量、即时编译后的代码等数据。方法区可以看作是堆的一个逻辑部分。不同于堆,方法区的垃圾回收频率较低。

6. 运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分,用于存储编译时生成的各种字面量和符号引用。运行时常量池在类加载后创建,包含类的各种信息,比如类名、字段名、方法名以及对应的描述符等。

7. 直接内存(Direct Memory)

直接内存并不是JVM规范中明确规定的内存区域,但它确实被广泛使用。直接内存是在JVM之外,由操作系统直接分配的内存,通过java.nio包中的ByteBuffer类来操作。直接内存的分配不受堆大小的限制,但受制于操作系统的内存大小。

运行时数据区的图示

sql 复制代码
--------------------------------
|         堆(Heap)           |
|   -------------------------  |
|  |       新生代(Young)    | |
|  |  ---------------------   | |
|  | | 伊甸区   | 幸存者区0  | | |
|  | | (Eden)  | (S0)       | | |
|  | |         |            | | |
|  |  ---------------------   | |
|  |  ---------------------   | |
|  | | 幸存者区1           | | |
|  | | (S1)               | | |
|  |  ---------------------   | |
|   -------------------------  |
|   -------------------------  |
|  |        老年代(Old)     | |
|  |                         | |
|   -------------------------  |
--------------------------------
|        方法区(Method Area)  |
|   -------------------------  |
|  |   运行时常量池(RCP)    | |
|   -------------------------  |
--------------------------------
|      程序计数器(PC Register)|
--------------------------------
|   Java虚拟机栈(JVM Stack)   |
|   -------------------------  |
|  |    栈帧(Stack Frame)    | |
|  |  ---------------------   | |
|  | | 局部变量表           | | |
|  | | 操作数栈             | | |
|  | | 动态链接             | | |
|  | | 方法返回地址         | | |
|  |  ---------------------   | |
|   -------------------------  |
--------------------------------
|    本地方法栈(Native Stack) |
--------------------------------

总结

JVM的运行时数据区是支持Java程序执行的关键组成部分。每个区域都有其特定的用途和特点,这些区域共同工作,支持Java程序的运行和内存管理。理解这些数据区的功能和相互关系,对于优化Java应用程序性能和解决内存问题具有重要意义。

相关推荐
QING6186 分钟前
Kotlin 中 == 和 === 的区别
android·kotlin·app
林十一npc12 分钟前
MySQL索引与视图综合应用示例解析
android·前端·mysql
bing_1582 小时前
JVM 类加载器在什么情况下会加载一个类?
java·jvm
QING6182 小时前
Kotlin containsValue用法及代码示例
android·kotlin·源码阅读
QING6182 小时前
Kotlin coerceAtMost用法及代码示例
android·kotlin·源码阅读
QING6182 小时前
Kotlin commonSuffixWith用法及代码示例
android·kotlin·源码阅读
QING6182 小时前
Kotlin coerceAtLeast用法及代码示例
android·kotlin·源码阅读
光军oi3 小时前
Mysql从入门到精通day5————子查询精讲
android·数据库·mysql
明天不下雨(牛客同名)8 小时前
为什么 ThreadLocalMap 的 key 是弱引用 value是强引用
java·jvm·算法
鸿蒙布道师12 小时前
鸿蒙NEXT开发Base64工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei