生产中的Java G1垃圾收集

时间:2010-02-12 18:11:55

标签: java garbage-collection java-7 g1gc

由于Java 7将默认使用新的G1垃圾收集,Java是否能够处理一个数量级更大的堆而不会产生“破坏性”的GC暂停时间?有人在生产中实际实施了G1,你的经历是什么?

公平地说,我唯一一次看到非常长的GC暂停是非常大的堆,远远超过工作站会有的。澄清我的问题; G1将打开数百GB的网关? TB?

16 个答案:

答案 0 :(得分:58)

我一直在用大量的应用程序测试它:60-70GB分配给堆,随时使用20-50GB。有了这些应用,说你的里程可能会有所不同,这是轻描淡写的。我在Linux上运行JDK 1.6_22。次要版本很重要 - 在大约1.6_20之前,G1中存在导致随机NullPointerExceptions的错误。

我发现它非常擅长保持在你大部分时间给你的暂停目标。默认似乎是100毫秒(0.1秒)暂停,我一直告诉它做一半(-XX:MaxGCPauseMillis = 50)。然而,一旦它的内存变得非常低,它就会发生恐慌并完成一个完整的世界垃圾收集。 65GB,需要30秒到2分钟。 (CPU的数量可能没有区别;它可能受到总线速度的限制。)

与CMS(不是默认服务器GC,但它应该用于Web服务器和其他实时应用程序)相比,典型的暂停更加可预测,并且可以缩短。到目前为止,我已经有了更好的运气与CMS的巨大停顿,但这可能是随机的;我每24小时只看几次。我不确定哪一个在我的生产环境中更合适,但可能是G1。如果甲骨文不断调整它,我怀疑G1最终将成为明显的赢家。

如果您对现有的垃圾收集器没有问题,那么现在没有理由考虑G1。如果您正在运行低延迟应用程序(例如GUI应用程序),则G1可能是正确的选择,MaxGCPauseMillis设置得非常低。如果您正在运行批处理模式应用程序,G1不会为您购买任何东西。

答案 1 :(得分:34)

听起来G1的要点是暂停时间较短,甚至可以指定最大暂停时间目标。

垃圾收集不仅仅是一个简单的“嘿,它已经完整,让我们一次性移动所有东西并重新开始”处理 - 它是非常复杂的,多层次的,后台线程系统。它可以在后台完成大部分维护而不会暂停,它还可以在运行时使用系统预期模式的知识来帮助 - 比如假设大多数对象在创建后就死了,等等。

我想说GC暂停时间将会继续改善,而不会在将来的版本中恶化。

编辑:

在重新阅读时,我发现我每天都使用Java - Eclipse,Azureus和我开发的应用程序,自从我看到暂停以来,这已经很长时间了。不是一个重要的停顿,但我的意思是任何暂停。

当我右键单击Windows资源管理器时,或者(偶尔)当我连接某些USB硬件时,我已经看到了暂停,但是使用Java ---根本没有。

GC仍然是个问题吗?

答案 2 :(得分:14)

虽然我没有在生产中测试G1,但我认为我会评论说,如果没有“大量”堆积的情况,GC已经存在问题。具体而言,只有2或4场演出的服务可能会受到GC的严重影响。年轻代GC通常没有问题,因为它们以一位数毫秒(或最多两位数)完成。但老一代的收藏品问题更多,因为他们需要花几秒钟才能使用1 gig或更高的旧版本。

现在:理论上CMS在那里可以提供很多帮助,因为它可以同时运行大部分操作。然而,随着时间的推移,将会出现无法做到这一点并且不得不回归“停止世界”收集的情况。当发生这种情况时(比如1小时之后 - 不经常,但仍然经常发生),好吧,坚持你的帽子。可能需要一分钟或更长时间。对于试图限制最大延迟的服务而言,这尤其成问题;而不是采用25毫秒来提供请求,现在需要10秒或更长时间。为了给侮辱客户增加伤害,通常会超时请求并重试,从而导致进一步的问题(又名“狗屎风暴”)。

这是G1希望帮助很多的一个领域。我曾在一家大公司工作,为存储和消息调度提供云服务;我们不能使用CMS,因为虽然它大部分时间比并行品种更好,但它有这些崩溃。所以大约一个小时的事情很好;然后东西击中了粉丝......因为服务是基于集群的,当一个节点遇到麻烦时,其他节点通常会跟随(因为GC引起的超时导致其他节点认为节点已经崩溃,导致重新路由)。 / p>

我认为GC不是应用程序的问题,甚至非集群服务也可能不那么受影响。但是越来越多的系统被集群化(特别是感谢NoSQL数据存储),并且堆大小正在增长。 OldGen GC与堆大小超线性相关(意味着,如果实时数据集的大小也增加一倍,那么堆大小加倍会使GC时间加倍)。

答案 3 :(得分:13)

Azul的首席技术官Gil Tene在他的Understanding Java Garbage Collection and What You Can Do about It演示文稿中对与垃圾收集相关的问题进行了很好的概述,并对各种解决方案进行了回顾,本文还有其他细节:http://www.infoq.com/articles/azul_gc_in_detail。< / p>

我们的Zing JVM中的Azul的C4垃圾收集器既是并行的又是并发的,并且对新旧代使用相同的GC机制,在两种情况下同时工作和压缩。最重要的是,C4没有世界末日的回落。所有压缩都与正在运行的应用程序同时执行。我们的客户运行非常大(数百GB),GC的暂停时间更短<10毫秒,根据应用的不同,通常不到1-2毫秒。

CMS和G1的问题在于,在某些时候必须压缩Java堆内存,并且这两个垃圾收集器都会停止世界/ STW(即暂停应用程序)以执行压缩。因此,虽然CMS和G1可以推出STW暂停,但它们并没有消除它们。然而,Azul的C4确实完全消除了STW暂停,这就是为什么Zing即使对于巨大的堆大小也有如此低的GC暂停。

为了纠正先前回答中的陈述,Zing不需要对操作系统进行任何更改。它就像未经修改的Linux发行版上的任何其他JVM一样运行。

答案 4 :(得分:12)

我们已经使用了近两年的G1GC。它在我们的关键任务事务处理系统中表现出色,并证明它是高吞吐量,低暂停,并发和优化大量内存管理的强大支持。

我们正在使用以下JVM设置:

-server -Xms512m -Xmx3076m -XX:NewRatio=50 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000 -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime

<强>更新

-d64 -server -Xss4m -Xms1024m -Xmx4096m -XX:NewRatio=50 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:-DisableExplicitGC -XX:+AggressiveOpts -Xnoclassgc -XX:+UseNUMA -XX:+UseFastAccessorMethods -XX:ReservedCodeCacheSize=48m -XX:+UseStringCache -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000

答案 5 :(得分:8)

G1收集器减少了完整收藏的影响。如果你有一个应用程序,你已经减少了对完整集合的需求,那么Concurrent map Sweep collector也同样好,根据我的经验,缩短了收集时间。

答案 6 :(得分:5)

似乎最终官方支持G1启动JDK7u4,请参阅RN for JDK7u4 http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html

从我们对大型JVM的测试结果来说,调优的CMS仍然比G1好,但我想它会更好。

答案 7 :(得分:4)

CMS即使您在不累积终身对象的情况下运行它也会导致性能缓慢下降。这是因为G1应该避免的内存碎片化。

只有付费支持才能获得关于G1的神话只是一个神话。 Sun和现在Oracle已经在JDK页面上澄清了这一点。

答案 8 :(得分:4)

G1 GC应该更好用。但如果设置-XX:MaxGCPauseMillis过于激进,垃圾收集速度会太慢。这就是为什么在David Leppik的例子中触发了完整的GC。

答案 9 :(得分:4)

我刚刚在Terracotta Big Memory项目中实施了G1 Garbage Collector。在处理不同类型的收集器时,G1给出了最佳结果,响应时间不到600毫秒。

您可以找到测试结果(共26个)here

希望它有所帮助。

答案 10 :(得分:4)

最近我被搬离了

CMS到G1GC,4G堆&amp;服务器上的8核处理器,JDK 1.7.45

(JDK 1.8.x G1GC优于1.7,但由于一些限制,我必须坚持1.7.45版本)

我已配置以下关键参数,并将所有其他参数保留为默认值。

-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n apart from -Xms and -Xmx

如果您想微调这些参数,请查看此oracle文章。

主要观察结果:

  1. 内存使用与G1GC一致,不像高和低。 CMS的低点
  2. 与CMS相比,最大GC暂停时间较短
  3. 与CMS相比,G1GC中垃圾收集的时间有点高。
  4. 与CMS相比,主要馆藏数量几乎可以忽略不计
  5. 与CMS相比较小的集合数量
  6. 但我仍然很高兴Max GC暂停时间少于CMS。我将Max GC暂停时间设置为 1.5秒,此值尚未超过。

    相关的SE问题:

    Java 7 (JDK 7) garbage collection and documentation on G1

答案 11 :(得分:3)

我最近将部分Twicsy迁移到具有128GB RAM的新服务器,并决定使用1.7。我开始使用与1.6一样的所有相同的内存设置(我有几个实例正在运行各种各样的事情,从500mb的堆到15GB,现在是一个40GB的新版本)并且根本不能很好地运行。 1.7似乎使用了比1.6更多的堆,并且我在头几天遇到了很多问题。幸运的是我有大量的RAM可以使用并且在我的大多数进程中增加了RAM,但仍然存在一些问题。我的正常MO是使用非常小的最小堆大小16m,即使最大堆数为几千兆字节,然后打开增量GC。这使停顿保持在最低限度。现在这不起作用,我不得不将最小大小增加到我预期在堆中平均使用的大小,并且这已经很好地解决了。我仍然打开增量GC,但我会在没有它的情况下尝试。现在没有任何停顿,事情似乎运行得非常快。所以,我认为这个故事的寓意是不要指望你的记忆设置从1.6到1.7完美地转换。

答案 12 :(得分:2)

G1使应用程序变得更加敏捷:应用程序的鲁棒性将提升 - 应用程序可以命名为“软实时”。这是通过将两种GC运行(小的次要和一次Tenured Ten)替换为相同大小的GC运行来完成的。

有关详细信息,请查看以下内容: http://geekroom.de/java/java-expertise-g1-fur-java-7/

答案 13 :(得分:1)

我正在使用Java,用于小型和大型堆,并且每天都会出现GC和Full GC的问题,因为约束可能比其他更严格:在某些环境中,0.1秒的清除剂GC或完全GC,简单地杀死fonctionnalité,并且具有细粒度的配置和功能很重要(CMS,iCMS,其他......目标是在这里使用近乎实时的处理具有最佳的响应时间(这里实时处理通常是25 ms),基本上,GC人体工程学和heuristique的任何改进都是受欢迎的!

答案 14 :(得分:1)

我在Java 8上使用G1GC,在Groovy(也是Java 8)上使用G1GC,我正在进行各种工作负载,而且整体上G1GC的工作原理如下:

  • 内存使用率非常低,例如与默认Java设置相比,100MB而不是500MB

  • 响应时间一致且非常低

  • 在最坏情况下使用G1GC时,默认设置和G1GC之间的性能降低了20%(没有调优,单线程应用程序)。考虑到良好的响应时间和较低的内存使用率,并没有太多考虑。

  • 从多线程的Tomcat运行时,整体性能提高30%,内存使用率也低得多,因为响应时间要低得多。

总的来说,当使用各种各样的工作负载时,G1GC对于多线程应用程序来说是非常好的Java 8收集器,甚至对于单线程也有一些好处。

答案 15 :(得分:0)

不建议使用java8 w / G1GC进​​行浮点计算,使用类似热点的JVM。它对应用程序的完整性和危险性都很危险。精度。

https://bugs.openjdk.java.net/browse/JDK-8148175

JDK-8165766

JDK-8186112