JAVA面试-JVM篇 03-JVM运行时数据区哪些是线程私有的哪些是共享的

文章概述

JVM运行时数据区是Java程序运行时的内存划分方案,理解哪些区域是线程私有的、哪些是共享的,是JVM调优和故障排查的基础。本文用一张总图、两张分类流程图和一张对比表格,帮你一次性理清。


一、整体架构一览

线程共享

线程私有

程序计数器

Java虚拟机栈

本地方法栈

方法区/元空间

线程1

线程2

...

所有线程共享

口诀:两栈一计数器私有,堆与方法区共享。


二、线程私有的三个区域

每个线程启动时都会独立创建一份,互不干扰。

线程创建

分配程序计数器

分配Java虚拟机栈

分配本地方法栈

记录当前执行的字节码地址

唯一不会OOM的区域

存储栈帧:局部变量表/操作数栈/动态链接/出口

异常:StackOverflowError / OutOfMemoryError

为native方法服务

HotSpot中合并到虚拟机栈

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

  • 当前线程所执行的字节码行号指示器
  • 分支、循环、跳转、异常恢复等都依赖它
  • 唯一一个不会抛出 OOM 的区域

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

每个方法调用都会创建一个栈帧入栈,方法结束则出栈。

栈帧组成 说明
局部变量表 存储方法参数和方法内定义的局部变量
操作数栈 字节码指令执行时的临时数据存储区
动态链接 指向运行时常量池中该方法的符号引用
方法出口 方法正常/异常返回时恢复上层调用者的状态

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

native 方法服务。HotSpot 虚拟机将它与虚拟机栈合二为一。


三、线程共享的两个区域

所有线程共享同一份数据,是垃圾回收和内存调优的重点关注区域。

线程共享区域


存储所有对象实例和数组

方法区/元空间
存储类信息/常量/静态变量/JIT代码

年轻代

老年代

运行时常量池
编译期生成的各种字面量和符号引用

1. 堆(Heap)

  • Java 内存管理中最大的一块
  • 所有对象实例和数组都在这里分配
  • 垃圾回收的主战场,分代回收的基础
  • 可细分为:年轻代(Young Gen)、老年代(Old Gen)

2. 方法区(元空间 Metaspace)

  • 存储已被加载的类信息、常量、静态变量、JIT编译后的代码
  • JDK8 后用元空间替代永久代,从JVM内存移到本地内存
  • 包含运行时常量池,存放编译期生成的字面量和符号引用

四、完整总结

JVM运行时数据区

线程私有

线程共享

程序计数器

Java虚拟机栈

本地方法栈

方法区/元空间

运行时常量池

区域 线程私有/共享 存储内容 是否OOM
程序计数器 私有 当前线程执行的字节码地址
Java虚拟机栈 私有 栈帧(局部变量表、操作数栈等)
本地方法栈 私有 native方法调用信息
共享 对象实例、数组
方法区/元空间 共享 类信息、常量、静态变量、JIT代码

更多推荐