JVM 哪些区域是线程私有的?哪些是线程共享的?

JVM 运行时数据区(Runtime Data Areas)根据线程共享与否,可以分为两大类:线程私有区域和线程共享区域。

1. 线程私有区域 (Thread-Private):

每个线程都有自己独立的一份,生命周期与线程相同(随线程创建而创建,随线程销毁而销毁)。

  • 程序计数器 (Program Counter Register):

    • 作用: 记录当前线程正在执行的字节码指令的地址(行号)。
    • 特点:
      • 非常小的一块内存区域。
      • 线程私有,每个线程都有自己的程序计数器。
      • 如果线程正在执行的是 Java 方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址。
      • 如果线程正在执行的是 Native 方法,程序计数器的值为空 (Undefined)。
      • 是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。
    • 为什么需要:
      • Java 虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的。在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。
      • 为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
  • 虚拟机栈 (VM Stack):

    • 作用: 存储方法调用的局部变量表、操作数栈、动态链接、方法出口等信息。
    • 特点:
      • 线程私有,每个线程都有自己的虚拟机栈。
      • 栈帧 (Stack Frame): 每次方法调用都会创建一个栈帧,用于存储方法的局部变量、操作数栈、动态链接、方法出口等信息。方法执行完毕后,栈帧会被销毁。
      • 局部变量表 (Local Variable Table): 存放方法参数和方法内部定义的局部变量。
      • 操作数栈 (Operand Stack): 一个后入先出 (LIFO) 栈,用于存放方法执行过程中的操作数和中间结果。
      • 动态链接 (Dynamic Linking): 指向运行时常量池中该栈帧所属方法的引用,用于支持方法调用过程中的动态链接。
      • 方法出口 (Return Address): 记录方法返回时应该跳转到的指令地址。
      • 异常:
        • StackOverflowError: 线程请求的栈深度大于虚拟机允许的深度。
        • OutOfMemoryError: 虚拟机栈无法申请到足够的内存(如果可以动态扩展)。
    • 与方法调用的关系:
      • 每个方法调用对应一个栈帧。
      • 方法的参数和局部变量存储在栈帧的局部变量表中。
      • 方法执行过程中的计算和操作在操作数栈上进行。
  • 本地方法栈 (Native Method Stack):

    • 作用: 与虚拟机栈类似,但用于支持 native 方法(使用 C、C++ 等编写的方法)的执行。
    • 特点:
      • 线程私有,每个线程都有自己的本地方法栈。
      • 具体的实现方式由虚拟机决定(HotSpot VM 中,本地方法栈和虚拟机栈是合二为一的)。
      • 异常:
        • StackOverflowError
        • OutOfMemoryError

2. 线程共享区域 (Thread-Shared):

所有线程共享同一份,生命周期与 JVM 相同(随 JVM 启动而创建,随 JVM 关闭而销毁)。

  • 堆 (Heap):

    • 作用: 存储对象实例和数组。
    • 特点:
      • 所有线程共享。
      • 是 JVM 中最大的一块内存区域。
      • 是垃圾回收的主要区域。
      • 逻辑上连续, 物理上可以不连续.
      • 可以划分为新生代(Young Generation)和老年代(Old Generation)。
        • 新生代又可以划分为 Eden 区、Survivor from 区和 Survivor to 区。
      • 异常:
        • OutOfMemoryError: 如果堆中没有足够的内存分配给新的对象,并且堆也无法再扩展时,抛出此异常。
    • 与对象创建的关系:
      • 几乎所有的对象实例和数组都在堆上分配内存。
      • new 关键字创建的对象会被分配到堆中。
  • 方法区 (Method Area):

    • 作用: 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
    • 特点:
      • 所有线程共享。
      • 在 HotSpot VM 中,方法区也被称为“非堆”(Non-Heap)或“永久代”(Permanent Generation,JDK 1.7 及之前)/“元空间”(Metaspace,JDK 1.8 及之后)。
        • 永久代 (PermGen): 使用 JVM 内存。容易出现 OutOfMemoryError: PermGen space
        • 元空间 (Metaspace): 使用本地内存 (Native Memory)。不容易出现 OutOfMemoryError,但需要注意防止本地内存耗尽。
      • 运行时常量池 (Runtime Constant Pool): 方法区的一部分,存放编译期生成的各种字面量和符号引用,以及运行时产生的常量。
    • 异常:
      • OutOfMemoryError: 如果方法区无法满足内存分配需求,抛出此异常。
    • 与类加载的关系:
      • 类加载器加载的类信息存储在方法区中。
      • 类的静态变量存储在方法区中。
      • 类的常量存储在运行时常量池中。

总结:

内存区域线程共享性主要用途异常
程序计数器私有记录当前线程正在执行的字节码指令的地址。OutOfMemoryError
虚拟机栈私有存储方法调用的局部变量表、操作数栈、动态链接、方法出口等信息。StackOverflowErrorOutOfMemoryError
本地方法栈私有支持 native 方法的执行。StackOverflowErrorOutOfMemoryError
共享存储对象实例和数组。OutOfMemoryError
方法区共享存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。OutOfMemoryError
运行时常量池共享存放编译期生成的各种字面量和符号引用,以及运行时产生的常量。(属于方法区)

图示:

+-------------------------------------------------------------------------------------+
|                                     JVM 运行时数据区                                    |
+-------------------------------------------------------------------------------------+
| +---------------------+  +---------------------+  +---------------------+           |
| |     线程 1          |  |     线程 2          |  |     线程 N          |           |
| +---------------------+  +---------------------+  +---------------------+           |
| | 程序计数器           |  | 程序计数器           |  | 程序计数器           | (私有)   |
| | 虚拟机栈             |  | 虚拟机栈             |  | 虚拟机栈             | (私有)   |
| | 本地方法栈           |  | 本地方法栈           |  | 本地方法栈           | (私有)   |
| +---------------------+  +---------------------+  +---------------------+           |
|                                                                                     |
| +---------------------------------------------------------------------------------+ |
| |                                     堆 (Heap)                                   | | (共享)
| | +---------------------------------+  +---------------------------------+ | |
| | |       新生代 (Young)             |  |        老年代 (Old)              | | |
| | | +-------+ +-------+ +-------+ |  +---------------------------------+ | |
| | | | Eden  | |  S0   | |  S1   | |                                          | |
| | | +-------+ +-------+ +-------+ |                                          | |
| | +---------------------------------+                                          | |
| +---------------------------------------------------------------------------------+ |
|                                                                                     |
| +---------------------------------------------------------------------------------+ |
| |                         方法区 (Method Area) / 元空间 (Metaspace)                   | | (共享)
| | +---------------------------------+                                               | |
| | |            类信息               |                                               | |
| | |            常量                 |                                               | |
| | |          静态变量              |                                               | |
| | |       JIT 编译后的代码          |                                               | |
| | |      运行时常量池             |                                               | |
| | +---------------------------------+                                               | |
| +---------------------------------------------------------------------------------+ |
+-------------------------------------------------------------------------------------+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值