🧐 线程隔离
- 程序计数器
- 虚拟机栈
- 本地方法栈
☺️ 线程共享
- 方法区
- 堆
🎋 程序计数器
当前线程执行字节码的行号指示器。
唯一一个不会出现 OutOfMemoryError
的内存区域,随线程的创建而创建,随线程的结束而死亡。
🎋 虚拟机栈
每一次方法的调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。
当线程请求栈的深度超过当前 Java 虚拟机最大深度时,会抛出 StackOverFlowError
。
局部变量表
存放编译期可知的各种数据类型,对象引用地址。
操作数栈
方法执行过程中的计算结果,计算过程中产生的临时变量。
动态链接
服务于一个方法需要调用其他方法的场景。
方法返回地址
- 正常返回(return)
- 异常返回(Exception)
🎋 本地方法栈
本地方法栈用于虚拟机执行 Native 方法,具体与虚拟机栈类似。
🎍 方法区
方法区是 Java 虚拟机的抽象概念。实现方式在不同虚拟机中可能不同。
- JDK 8 之前,HotSpot 虚拟机使用永久带实现方法区
JDK 8 及之后,使用元空间(直接内存)实现
字符串常量池与静态变量转移到了堆中。
类的元信息
类名,访问修饰符,字段描述,方法描述等
运行时常量池
存放编译后的各种字面量,符号引用,常量(final)池表等
字符串常量池
JVM 为了减少字符串对内存的消耗,并提升性能,专门开辟的区域
静态变量
类变量(static)
🎍 堆
用来存放和管理对象实例,几乎所有的对象实例都在这里分配。(存在逃逸分析,栈上分配,有些对象不一定在堆中)
Java 堆是垃圾回收的主要区域,因此也被称为 GC 堆。
JDK 8 之前,堆被分为
- 新生代(Eden、Survivor0、Survivor1)
- 老年代
- 永久代(方法区也由永久代实现)
JDK 8 之后,永久代被取消
大部分情况下,对象首先会在新生代的 Eden 区进行分配;在一次垃圾回收后,如果对象还存活,会进入 S0 或 S1;当对象年龄增长到一定程度(默认 15),或累积的年龄超过了 Survivor 的一半,会晋升到老年代。
参考
- 图来源于网络。
- 深入理解 Java 虚拟机