【java】HotSpot 虚拟机 java 对象分配与回收

描述 HotSpot 虚拟机的对象分配与回收

堆内存分区

堆内存分为 3 个区域,分别是

  • 新生代(Young Generation):用于存放新产生的对象。新生代又分为 1 个 Eden 区和 2 个 Survivor 区,默认比例为8:1:1。
  • 老年代(Tenured Generation):用于存放被长期引用的对象。
  • 永久代(Permanent Generation):用于存放 Class,method 元信息。

永久代其实是 HotSpot 虚拟机方法区,仅仅是因为 HotSpot 虚拟机使用永久代实现方法区而已,对于其他虚拟机是不存在永久代的说法

jvm 内存区域

内存分配与回收策略

大多数情况下,对象在新生代的 Eden 区分配。当 Eden 区没有足够空间进行分配时,虚拟机发起一次 Minor GC。而大对象直接进入老年代。

每个对象有一个年龄计数器,对象在 Eden 区出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 区容纳的话,对象会被移动到 Survivor 空间,年龄设定为 1。此后每经过一次 Minor GC,存活的对象的年龄就加 1, 当年龄增加到一定程度,对象就被移入老年代。

在发生 Minor GC 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间。如果成立,那么 Minor GC 是安全的,如果不成立则虚拟机会检查 HandlePromotionFailure 设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次 Minor GC,如果小于,或者 HandlePromotionFailure 设置不允许,那进行一次 Full GC

  • 新生代GC(Minor GC):指发生在新生代的垃圾收集。Minor GC 一般比较频繁,速度也快
  • 老年代GC(Major GC / Full GC):指发生在老年代的垃圾收集,一般会比 Minor GC 慢 10 倍以上

垃圾收集算法

  1. 标记-清除算法(Mark-Sweep)
    算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记后统一回收所有被标记的对象
    不足:1.标记和清除两个过程的效率不高 2.标签清除后产生内存碎片
  2. 复制算法(Copying)
    将可用内存分为两块,每次只使用其中一块。当一块内存用完了,就将还存活的对象复制到另一块上,然后清理掉用过的那一块
    不足:将可用内存缩小了一半
  3. 标记-整理算法
    算法分为“标记”和“整理”两个阶段:首先标记出所有需要回收的对象,让所有存活的对象都向内存一端移动,减少内存碎片
  4. 分代收集算法
    根据对象存活周期,将内存划分为几块,根据各个块的特点采用最适当的收集算法。这是目前商业虚拟机都使用的收集算法

垃圾收集器

  1. Serial 收集器
    单线收集器。进行垃圾收集时,必须暂停所有工作线程(被叫作 Stop The World,STW),直到收集结束
  2. Serial Old 收集器
    是 Serial 收集器的老年代版本,同样是一个单线程收集器,使用“标记-整理”算法。
  3. ParNew 收集器
    是 Serial 收集器的多线程版本
  4. Parallel Scavenge 收集器
    使用复制算法
  5. Parallel Old 收集器
    Parallel Scavenge 收集器的老年代版本,使用多线程的“标记-整理”算法
  6. CMS 收集器(Concurrent Mark Sweep)
    算法由 4 个步骤完成

    1. 初始标记。仅标记 GC Root 能直接关联到的对象
    2. 并发标记。并发进行 GC Tracing
    3. 重新标记。修正并发标记期间因用户程序动作而带来的改动。
    4. 并发清除

    其中初始标记、重新标记两个步骤需要停止所有工作线程。
    优点:并发收集,低停顿。
    缺点:CPU资源敏感,并发虽然不会导致用户线程停顿,但会占用了 CPU 而让应用程序变慢无法处理浮动垃圾,由于并发清理时用户线程还在运行,这个时候所产生的垃圾无法在当次收集中处理,必须等下一次空间碎片,“清除”算法所产生

  7. G1 收集器
    将整个堆内存分为多个独立的 Region,将进行回收。对比其他收集器有如下特点:

    1. 并行与并发,使用多个 CPU 来缩短 Stop-The-World 停顿时间
    2. 分代收集
    3. 空间整合,不会产生内存碎片
    4. 可预测的停顿,可指定在一个长度为 M 毫秒的时间片段内,消耗在垃圾收集上的时间不得超过 N 毫秒
    5. 作用于整个堆,而不将需要分新生代和老年代

各个收集器的关系如下图,如果有连线,说明两个收集器可以配合使用

各种 GC 算法关系