java9 g1垃圾收集器_Java 9中默认为G1垃圾收集器的情况

java9 g1垃圾收集器

在前面的几篇文章中,我已经在InfoQ上介绍并讨论了“垃圾第一垃圾收集器” -G1:一个由所有垃圾收集器来统治它们以及调整垃圾第一垃圾收集器的技巧 。

今天,我想讨论一下JEP 248 ,即将G1设为针对OpenJDK 9的默认GC的建议。从OpenJDK 8开始,吞吐量GC(也称为Parallel GC)以及最近的ParallelOld GC(ParallelOld意味着两者-XX:+ UseParallelGC和-XX:+ UseParallelOldGC已启用)已成为OpenJDK的默认GC。 任何想使用其他垃圾收集算法的人都必须在命令行上显式启用它。 例如,如果要使用G1 GC,则需要在命令行上使用-XX:+ UseG1GC进​​行选择。

将G1 GC设置为OpenJDK 9的默认GC的提案一直是引起社区关注的主要原因,引起了一些惊人的讨论,并最终导致了对原始提案的更新,以便将条款纳入提供还原为使用并行GC作为默认设置的功能。

那么,为什么要使用G1 GC?

您可能熟悉软件优化的权衡:可以针对延迟,吞吐量或占用空间对软件进行优化。 GC优化也是如此,并反映在各种流行的GC中。 您也可以专注于这三个中的两个,但是要针对这三个进行优化非常困难。 OpenJDK HotSpot GC算法旨在优化这三种算法之一-例如,优化串行GC以减少占用空间,优化并行GC以提高吞吐量,并(主要)优化并发标记和扫描GC(通常称为CMS)以最小化GC引起的延迟并提供了改进的响应时间。 那么,为什么我们需要G1?

G1 GC可以长期替代CMS。 当前状态的CMS有一个病理问题,它将导致并发模式故障,最终导致完整的堆压缩集合。 您可以调整CMS以推迟当前的单线程全堆压缩集合,但是最终无法避免。 您可以调整CMS来推迟当前的单线程全堆压缩回退集合,但最终无法避免。 将来,可以改进后备集合,以使用多个GC线程来加快执行速度。 但同样,无法避免完整的压缩集合。

另一个重要的一点是,即使对于经验丰富的GC工程师而言,CMS的维护也被证明是非常困难的。 活跃的HotSpot GC维护人员的目标之一就是保持CMS的稳定。

此外,CMS GC,Parallel GC和G1 GC均通过不同的GC框架实现。 维护三个不同的GC的成本都很高,每个GC都使用自己独特的GC框架。 在我看来,G1 GC的区域化堆框架(集合的单位是一个区域,并且各个此类区域可以组成连续的Java堆中的各个代)是未来的发展方向-IBM拥有其Balanced GC,Azul拥有C4 ,最近有一个称为Shenandoah的OpenJDK提案。 看到类似的基于区域的基于吞吐量的吞吐量GC的实现并不奇怪,它可以提供并行GC的吞吐量和自适应调整大小的好处。 因此,有可能可以减少HotSpot中使用的GC框架的数量,从而降低维护成本,从而可以更快地开发新的GC功能。

G1 GC在OpenJDK 7更新4中得到了完全支持,从那时起,它在OpenJDK社区的大量帮助下变得越来越好,功能越来越强大。 要了解有关G1的更多信息,我强烈推荐前面提到的InfoQ文章,但让我总结一些关键要点:

  • G1 GC提供了一个区域化的堆框架。
    • 这有助于为后代提供巨大的可调性,因为现在集合的单位(一个区域)比世代本身小。 并且增加/减少世代大小就像从可用区域列表中添加/删除区域一样简单。 注意:即使整个堆是连续的; 特定世代中的区域不必是连续的。
  • G1 GC的设计原则是首先收集最多的垃圾。
    • G1具有针对年轻和混合收藏的独特收藏集(CSet)(有关更多信息,请参阅本文 )。 对于混合集合,集合集包括所有年轻区域和一些候选旧区域。 并发标记周期有助于识别这些候选的旧区域,并将它们有效地添加到混合收集集中。 与并行GC中提供的有限大小的可调参数或CMS中提供的大小和“标记起始”阈值设置相比,G1 GC中可用于旧一代的调整开关更直接,数量更多,并且提供更多的控制。 我在这里设想的未来是自适应G1 GC,它可以根据标记和收集周期中收集到的统计信息预测性地优化收集集和标记阈值。
    • (可以这么说)G1 GC的疏散失败也是“可调”的。 与CMS不同,G1中的碎片不是随时间累积的,不会导致昂贵的收集和并发模式故障。 在G1中,碎片是最小的,并且受可调参数控制。 不遵循正常分配路径的非常大的对象也会引入一些碎片。 这些非常大的对象(也称为“巨大对象”)直接从旧一代中分配到称为“巨大区域”的区域中。 (注意:要了解有关庞大对象和庞大分配的更多信息,请参阅本文 )。 但是,当这些巨大的物体死亡时,它们就会被收集起来,碎片也随之死亡。 在当前状态下,它有时仍可能只是堆区域和堆占用调优噩梦,尤其是当您尝试使用受限资源时。 但是同样,使G1算法更具适应性将导致最终用户不会遇到任何故障。
  • G1 GC可扩展!
    • G1 GC算法在设计时考虑了可伸缩性。 与ParallelGC进行比较,您可以根据堆大小和负载进行扩展,而不会影响应用程序的吞吐量。

为什么现在?

该提案是针对OpenJDK的9 OpenJDK的9一般可用性是针对2016年九月,这仍然是一个一年。 希望选择使用早期访问版本和候选发布版本的OpenJDK社区成员可以测试G1 GC作为默认GC的可行性,并有助于及时提供反馈,甚至提供代码更改。

同样,唯一受影响的最终用户是那些今天没有设置明确GC的用户。 在命令行上设置显式GC的用户不受此更改的影响。 未明确设置GC的用户将使用G1 GC代替Parallel GC,如果要继续使用Parallel GC,只需设置-XX:+ UseParallelGC(当前的默认设置即可启用并行GC线程用于年轻集合)在其JVM命令行上。 注意:在JDK 5更新6中引入了-XX:+ UseParallelOldGC; 对于所有最近的构建,您会发现,如果在JVM命令行上设置-XX:+ UseParallelGC,还将启用-XX:+ UseParallelOldGC,因此并行GC线程也将用于完整集合。 因此,如果您正在使用> JDK 6构建,则设置这些命令行选项中的任何一个都将提供与以前相同的GC行为。

什么时候您会选择G1 GC而不是并行GC?

如本文所述 ,并行GC不进行增量收集,因此最终牺牲了吞吐量的延迟。 对于较大的堆,随着负载增加,GC暂停时间也通常也会增加,这可能会损害与延迟相关的系统级别协议(SLA)。

G1可以帮助您以较小的堆占用空间交付响应时间SLA,因为G1的混合收集暂停应该比Parallel GC中的完整收集要短得多。

什么时候选择G1 GC而不是CMS GC?

在当前状态下,经过调整的G1可以并且将满足CMS GC由于碎片和并发模式故障而无法提供的延迟SLA。 混合集合的最坏情况下的暂停时间预计将比CMS将遇到的最坏情况下的完全压缩暂停更好。 如前所述,可以推迟但不能阻止CMS堆的碎片化。 一些与CMS一起工作的开发人员提出了一些变通方法,以通过将对象分配给类似大小的块来解决碎片问题。 但是这些都是围绕 CMS构建的变通办法; CMS的固有特性是易于碎片化,需要完整的压缩集合。 我也知道像Google这样的公司,他们通过OpenJDK源代码构建并运行自己的私有JDK,并通过更改特定源代码来满足他们的需求。 例如,为了减少碎片,一位Google工程师提到他们在(私有)CMS GC的备注阶段添加了一种增量压缩形式,并使CMS GC更加稳定(请参阅: http:// mail。 openjdk.java.net/pipermail/hotspot-dev/2015-July/019534.html )。

注意:增量压缩会自带成本。 在权衡特定用例的优势后,Google可能会添加增量压缩。

为什么JEP成为如此热门的话题?

许多OpenJDK社区成员对G1是否准备好迎接黄金时间表示了担忧。 成员们就他们在G1领域的经验发表了意见。 自从G1得到完全支持以来,它一直被誉为CMS的替代品。 但是社区对此感到担忧,因为现在感觉到G1实际上正在取代G1,而不是CMS。 因此,人们普遍认为,尽管可能存在将CMS与G1进行比较的数据(由于企业从CMS迁移至G1),但没有足够的数据将Parallel GC(当前的默认值)与G1(建议的默认值)进行比较。 另外,现场数据似乎表明大多数企业仍在使用默认GC,因此当G1成为默认GC时,肯定会观察到行为的变化。

也有观察发现,G1展示了一些重要的索引损坏问题(尽管很难重现),并且在将G1设置为默认值之前需要研究并纠正这些问题。

还有其他人问我们是否仍需要一个不基于“ 人体工程学 ”的默认GC。 (例如,从Java 5开始,如果您的系统被标识为“服务器级”系统,则默认JVM将更改为服务器VM,而不是客户端VM(参考: http : //docs.oracle.com/javase/7/ docs / technotes / guides / vm / server-class.html ))。

摘要

经过反复的反复,最终Oracle的性能架构师Charlie Hunt总结并提出了以下计划(请注意:以下摘录可从此处引用: http : //mail.openjdk.java.net/pipermail/hotspot-dev /2015-June/018804.html ):

  • “使G1成为JDK 9中的默认收集器,继续评估G1并增强JDK 9中的G1
  • 如果需要继续监控JDK 9预发行版和最新JDK 8更新版本中对G1的观察和体验,可以通过在JDK 9变为“通用”(2016年9月22日[1])之前恢复并行GC来减轻风险。
  • 解决了增强的人体工程学问题,以便在将来的观察结果表明需要时将默认的GC选择为单独的JEP。”

此外,Oracle Java SE Performance团队的Staffan Friberg敦促社区帮助收集关键指标的数据点。 为了简明起见,我对斯塔凡的信息进行了解释:

  • 启动时间:确保G1的基础结构复杂度不会在Java虚拟机(JVM)初始化时引入太多延迟;
  • 吞吐量:G1与吞吐量GC并驾齐驱。 G1也有写前和写后的障碍。 吞吐量度量标准是了解障碍可以对应用程序造成多少过载的关键。
  • 足迹:G1记得确实增加足迹的集合和集合集。 从现场收集的数据应提供足够的信息,以了解增加的占地面积所产生的影响。
  • 开箱即用的性能:使用默认GC的企业,很多时候也使用该GC提供的开箱即用的性能。 因此,了解G1的开箱即用性能非常重要。 在这里,GC的人体工程学和适应性起着重要的作用。

Staffan还帮助确定了当前使用默认GC算法的业务应用程序,这些业务应用程序将受到默认GC更改的影响。 同样,未指定GC的脚本或未在命令行上仅指定Java堆和生成大小的接口都会受到默认GC算法更改的影响。

致谢

我要感谢查理·亨特(Charlie Hunt)对本文的审阅。

翻译自: https://www.infoq.com/articles/Make-G1-Default-Garbage-Collector-in-Java-9/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

java9 g1垃圾收集器

你可能感兴趣的:(java9 g1垃圾收集器_Java 9中默认为G1垃圾收集器的情况)