JVM(Java虚拟机)运行时数据区
JVM运行时数据区包含方法区(存储类信息、常量等)、堆(对象实例存储区)、程序计数器(线程私有字节码指示器)、虚拟机栈(方法执行模型)和本地方法栈。其中方法区在不同JDK版本有永久代和元空间两种实现,堆分为新生代和老年代。程序计数器是唯一不会OOM的区域,其他区域在内存不足时可能抛出OutOfMemoryError或StackOverflowError。文章还提供了元空间配置建议和常见问题解决方案
JVM(Java虚拟机)运行时数据区由多个部分组成,每个部分都有其特定的目的和功能。以下是各个内存区域的详细说明:
-
方法区(Method Area):
-
方法区是所有线程共享的一部分内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
-
在HotSpot虚拟机中,方法区的具体实现形式为永久代(PermGen,在Java 7及之前版本)或元空间(Metaspace,在Java 8及之后版本)。当方法区需要的空间超过其允许的最大值时,会抛出
OutOfMemoryError。 -
推荐配置
-
普通web应用
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -
大型微服务或中间件
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -
动态类生成较多的应用
-XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1024m
🛠 如何确定合适的大小?
开启 GC 日志,观察是否有 Metaspace 相关的 Full GC 或扩容,如果频繁出现:
[GC (Metadata GC Threshold) ...] [Full GC (Metadata GC Threshold) ...]说明 Metaspace 快满了,需要扩容或设置更大的上限。
-
-
❗ 常见问题
问题 原因 解决方案 java.lang.OutOfMemoryError: Metaspace元空间耗尽 设置 -XX:MaxMetaspaceSize并适当调大频繁 Full GC 因 Metaspace 触发阈值 MetaspaceSize 太小 提高 -XX:MetaspaceSize类加载器泄漏导致元空间持续增长 ClassLoader 未正确释放 检查动态类加载逻辑,避免内存泄漏
-
-
Java堆(Heap):
- Java堆也是被所有线程共享的一块内存区域,它是垃圾收集器管理的主要区域,几乎所有的对象实例以及数组都要在堆上分配。
- 堆分为新生代(Young Generation)和老年代(Old Generation),其中新生代又分为Eden空间、From Survivor空间和To Survivor空间。如果堆内没有足够的空间完成实例分配,并且堆也无法再扩展时,将会抛出
OutOfMemoryError。
-
程序计数器(Program Counter Register):
- 程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。每个线程都有它自己的程序计数器,这是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
- 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是本地方法,则计数器的值为空(undefined)。
-
Java虚拟机栈(Java Virtual Machine Stacks):
- 同样地,每个线程都有私有的Java虚拟机栈,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域可能会抛出两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的深度(由
-Xss参数控制,默认一般为 1MB 左右),将抛出StackOverflowError。 - 如果虚拟机栈可以动态扩展,而在尝试扩展时无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,将会抛出
OutOfMemoryError。
- 如果线程请求的栈深度大于虚拟机所允许的深度(由
-
本地方法栈(Native Method Stack):
- 本地方法栈与虚拟机栈发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
- 在一些虚拟机实现中(如Sun HotSpot),直接把本地方法栈和虚拟机栈合二为一。同样,本地方法栈也可能抛出
StackOverflowError和OutOfMemoryError错误。
这些内存区域共同协作来支持Java应用程序的运行,每一个部分都承担着不同的职责,确保了程序能够高效稳定地执行。程序计数器由于其特殊的设计目的和使用方式,是唯一不会出现OutOfMemoryError的内存区域。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)