写点什么

不同 GC 和 堆内存总结

用户头像
学个球
关注
发布于: 8 小时前

GC 算法

  • 标记-复制。优点:存活的对象越少,复制需要的空间就越小;而且复制后的对象们内存空间排布紧凑,避免空间碎片的问题。缺点:有一部分空间被浪费。如果存活对象大且多的话复制成本比较高。适用每次 GC 存活对象小而美的情况。年轻代

  • 标记-清除。直接清除可回收对象,不进行内存整理。,优点:单次 STW 的时间可能要短一些。缺点:但是产生的内存碎片,可能导致内存总空间足够,但是没一块连续的空间存放对象的问题,内存利用率降低;对象放不下,可能触发额外的 GC。适用对象存活率高的情况。老年代

  • 标记-清除-整理。STW 时间可能会稍长一些,内存碎片问题得到解决。适用对象存活率高的情况。

Serial GC

-XX:+UseSerialGC

串行 GC 单线程执行,在 GC 期间其他业务线程均暂停,暂停的时间长。

串行 GC 对年轻代采用标记复制算法。对老年代使用标记-清除-整理算法。

串行 GC 简单直接,在单核 CPU 环境下比较适用。

-XX:+UseParNewGC

ParNew 收集器,多线程版本的 Serial。配合 CMS 使用。

Parallel GC

-XX:UseParallelGC -XX:UseParallelOldGC

使用的 GC 算法和串行的一样。

默认的 GC 线程数是 CPU core 数,该收集器的目标更倾向于提高系统吞吐量,有时候单次的 GC 暂停时间较长。

CMS GC

-XX:UseConcMarkSweepGC

对老年代没有整理操作,使用 free-list 进行内存空间的管理。默认的核心线程数 CPU 核数 / 4。

可以和业务线程并发执行,GC 暂停时间少。

G1 GC

打破整个分区的理论,把内存划分成多个小块进行管理。对每个小块的垃圾数量进行预估,优先回收垃圾多的 Region。可预期的垃圾停顿时间。

 

验证总结

首先需要提到的一点是 GC 的时间和存活的对象数量有关,和堆内存的大小关系没有那么大。

 

配置堆内存 512M,YGC 后年轻代存活对象大概 20M。

  • 串行 GC 利用单线程执行,GC 暂停的时间明显会比较长。在实际的测试下,在小堆内存空间的情况下,YGC 和并行 GC 的 YGC 差不多。FGC 使用的时间明显较长,大概是并行 GC 的一倍(存活对象 300M 左右)。老年代存活对象占用的空间大,整理移动的时间就长。

  • CMS GC 的老年代清理明显的暂停时间降低。在 GC 日志中有发现 concurrent mode failure 的情况。查询资料后明白,CMS 在 cleanup 是并发执行的,这时的对象引用关系发生改变,也可能有新的对象需要分配空间。如果没有预留足够的空间内存分配就会导致并发失败。可能重新 CMS ,或者 GC 退化成 Serial。

  • G1 GC 出现了 Humongous Allocation 因为大对象分配失败,触发了 initial-mark。也是重新标记,或者 GC 退化的问题。

 

堆内存越大,内存中可容纳的对象越多,GC 的次数随之减少,单次 GC 的暂停时间可能更长(取决于存活对象的数量)。

 

总的来说,注意不同 GC 策略采用的算法,以及设计的目的。比如 CMS 在于并发执行,提高系统响应。Parallel 更倾向于提高吞吐量;G1 GC 倾向于可配置可预估的暂停时间。

 

CMS - 老年代 没有整理,使用 free-list 管理回收内存;真正的 STW 时间小,但是步骤多,还有浮动垃圾,GC 退化问题。G1 GC 也存在 GC 退化问题。

 

配置堆内存的时候,注意 JVM 自身需要的内存和系统需要的内存,预留一定的空间。

-Xms -Xmx 直接一步到位,扩容的时候有性能的抖动。

年轻代和老年代的比例默认 1:2,新生代:from:to = 8:1:1,根据情况来调整。

根据对象晋升回收速率的计算,进行空间,晋升年龄的配置。

发布于: 8 小时前阅读数: 3
用户头像

学个球

关注

还未添加个人签名 2017.11.15 加入

还未添加个人简介

评论

发布
暂无评论
不同 GC 和 堆内存总结