JVM内存区域


JVM内存区域(重要!)

JDK1.8之前

JDK1.8之后

分为线程共享和线程私有的两种内存:

  • 线程私有
    • 程序计数器(唯一不会出现OutOfMemoryError 内存溢出错误的区域)
    • 虚拟机栈
    • 本地方法栈
  • 线程共享
    • 方法区(1.8之后去掉改为本地内存内的元空间)
      • 运行时常量池
  • 本地内存
    • 直接内存
    • 元空间

下面详细解释一下:

程序计数器

  • 唯一不会出现OutOfMemoryError 内存溢出错误的区域
  • 记录线程的暂停与继续执行的指令
  • 分支/循环/跳转等流程控制

虚拟机栈

  • 传递调用方法时的数据
  • 调用方法,栈帧入栈;方法结束(返回值/异常),栈帧出栈
  • 局部变量表:编译期可知的数据类型/对象引用
  • 两种错误
    • StackOverFlowError:JVM虚拟机栈容量不允许动态扩展
    • OutOfMemoryError:JVM虚拟机栈容量允许动态扩展但是超出内存

本地方法栈

  • 其实与JVM栈一样,不过调用的是Native本地方法

  • 线程共享

  • 最大的一块
  • 存放几乎所有对象实例及数组(JDK1.7之后不再那么绝对因为有逃逸分析

因为是垃圾回收主要负责的一块,也被称为GC堆。


下面内容涉及垃圾回收的东西了。

可以根据垃圾回收继续细分:

在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常被分为下面三部分:

  1. 新生代内存(Young Generation)
  2. 老生代(Old Generation)
  3. 永生代(Permanent Generation)

JVM堆内存结构-JDK7

JDK 8 版本之后方法区(HotSpot 的永久代)被彻底移除了(JDK1.7 就已经开始了),取而代之是元空间,元空间使用的是直接内存。

元空间

1
2
3
4
5
6
7
8
graph LR
b[Begin]--对象创建-->Eden区 --一次新生代垃圾回收仍旧存活--> age[年龄+1,进入s0/s1 ]--超过阈值-->进入老年代
b--大对象-->老年代
subgraph 新生代划分
新生代-->.Eden区
新生代-->Survivor区-->s0
Survivor区-->s1
end

大部分情况,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。

“Hotspot 遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了 survivor 区的一半时,取这个年龄和 MaxTenuringThreshold 中更小的一个值,作为新的晋升年龄阈值”。

  • 新生代
    • 新生代GC过程称为MinorGC,采用复制算法
  • 老年代
    • 存放长生命周期对象,大对象(默认2KB~128KB)
    • 老年代的CG过程称为MajorGC,采用标记-清除算法,不会频繁触发

方法区

(1.8之后去掉改为本地内存内的元空间)

方法区其实在Hotspot虚拟机中就是永久代(1.8之前),在1.8之后就是元空间

方法区与 Java 堆一样,是各个线程共享的内存区域。

它用于存储已被虚拟机加载的Class类信息、常量、静态变量、即时编译器编译后的代码等数据。

方法区有JVM内存上限限制,元空间只有系统限制。

运行时常量池

JDK1.7之前,常量池全在永久代。

JDK1.7,字符串常量池在堆,运行时常量池在永久代

JDK1.8之后,字符串常量池在堆,运行时常量池在元空间。

直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致 OutOfMemoryError 错误出现。

本机直接内存的分配不会受到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。

总结一下:

  • 线程私有
    • 程序计数器(流程控制,线程暂停)
    • 虚拟机栈(栈帧,方法调用)
    • 本地方法栈(Native方法)
  • 线程共享
    • 堆(包含字符串常量池,最大的内存区域,垃圾回收主要管理区域,存储对象/数组)
    • 方法区(永久代,后被替换为元空间)
    • 本地内存
      • 元空间(包含运行时常量池)
      • 直接内存(系统内存)

文章作者: SongX64
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SongX64 !
  目录