Featured image of post JVM 内存区域

JVM 内存区域

area

  • 🧐 线程隔离

    • 程序计数器
    • 虚拟机栈
    • 本地方法栈
  • ☺️ 线程共享

    • 方法区

🎋 程序计数器

当前线程执行字节码的行号指示器。

唯一一个不会出现 OutOfMemoryError 的内存区域,随线程的创建而创建,随线程的结束而死亡。

🎋 虚拟机栈

每一次方法的调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。

stack

当线程请求栈的深度超过当前 Java 虚拟机最大深度时,会抛出 StackOverFlowError

  • 局部变量表

    存放编译期可知的各种数据类型,对象引用地址。

  • 操作数栈

    方法执行过程中的计算结果,计算过程中产生的临时变量。

  • 动态链接

    服务于一个方法需要调用其他方法的场景。

  • 方法返回地址

    • 正常返回(return)
    • 异常返回(Exception)

🎋 本地方法栈

本地方法栈用于虚拟机执行 Native 方法,具体与虚拟机栈类似。

🎍 方法区

方法区是 Java 虚拟机的抽象概念。实现方式在不同虚拟机中可能不同。

  • JDK 8 之前,HotSpot 虚拟机使用永久带实现方法区

before

  • JDK 8 及之后,使用元空间(直接内存)实现

    字符串常量池与静态变量转移到了堆中。

after

  • 类的元信息

    类名,访问修饰符,字段描述,方法描述等

  • 运行时常量池

    存放编译后的各种字面量,符号引用,常量(final)池表等

  • 字符串常量池

    JVM 为了减少字符串对内存的消耗,并提升性能,专门开辟的区域

  • 静态变量

    类变量(static)

🎍 堆

用来存放和管理对象实例,几乎所有的对象实例都在这里分配。(存在逃逸分析,栈上分配,有些对象不一定在堆中)

Java 堆是垃圾回收的主要区域,因此也被称为 GC 堆。

  • JDK 8 之前,堆被分为

    • 新生代(Eden、Survivor0、Survivor1)
    • 老年代
    • 永久代(方法区也由永久代实现)
  • JDK 8 之后,永久代被取消

大部分情况下,对象首先会在新生代的 Eden 区进行分配;在一次垃圾回收后,如果对象还存活,会进入 S0 或 S1;当对象年龄增长到一定程度(默认 15),或累积的年龄超过了 Survivor 的一半,会晋升到老年代。

参考

  • 图来源于网络。
  • 深入理解 Java 虚拟机