生产中的Java G1垃圾收集
由于Java 7将会默认使用新的G1垃圾回收function,因此Java能够处理大一个数量级的堆而不会造成“破坏性”的GC暂停时间? 有没有人在生产中实际使用G1,你有什么经验?
公平地说,我看到真正长时间的GC暂停是非常大的,比工作站要多得多。 澄清我的问题; G1会打开数百GB的网关吗? TB?
这听起来像G1的一点是有较小的暂停时间,甚至到有能力指定一个最大的暂停时间目标。
垃圾收集不仅仅是一个简单的“嘿,它已经满了,让我们一下子把所有的东西都搬走了,重新开始” – 这是一个非常复杂的,多层次的,后台线程系统。 它可以在没有任何暂停的情况下在后台执行大部分维护工作,并且还可以在运行时使用系统预期模式的知识来帮助 – 例如假设大多数对象在创build后立即死亡等等。
我会说GC停顿时间将会继续改善,而不会恶化,随着未来的版本。
编辑:
在重读时,我发现我每天都在使用Java,Eclipse,Azureus和我开发的应用程序,而且自从我看到一个停顿之后,这是一个很长的时间。 不是一个重大的停顿,但我的意思是任何停顿。
当我右键单击Windows资源pipe理器或(偶尔)连接某些USB硬件时,我已经看到暂停,但用Java —没有。
GC仍然是一个问题吗?
我一直在testing一个沉重的应用程序:60-70GB分配给堆,随时使用20-50GB。 有了这些应用程序,说你的里程可能会有所不同,这是轻描淡写的。 我在Linux上运行JDK 1.6_22。 次要版本很重要 – 在1.6_20之前,G1中有一些错误导致随机的NullPointerExceptionexception。
我发现,在大部分时间内保持暂停的目标是非常好的。 默认情况下是100ms(0.1秒)的暂停,我已经告诉它做了一半(-XX:MaxGCPauseMillis = 50)。 但是,一旦内存变得非常低,就会惊慌失措,并且完全停止垃圾收集。 用65GB,需要30秒到2分钟。 (CPU的数量可能没有什么区别,它可能受到总线速度的限制。)
与CMS(不是默认的服务器GC,但应该用于Web服务器和其他实时应用程序)相比,典型的暂停更可预测,并且可以缩短得多。 到目前为止,我对CMS有更好的运气,可能是随机的, 我每24小时只看到几次。 我不确定哪一个更适合我的生产环境,但可能是G1。 如果甲骨文一直在调整它,我怀疑G1最终将成为赢家。
如果你现在的垃圾收集器没有问题,现在就没有理由考虑G1了。 如果您运行的是低延迟应用程序(如GUI应用程序),则G1可能是正确的select,MaxGCPauseMillis设置得非常低。 如果您正在运行批处理模式应用程序,G1不会为您购买任何东西。
尽pipe我还没有testing过G1的产品,但是我想我会评论说GC在没有“庞大”堆的情况下已经成问题了。 特别是只有2或4个演出的服务可能会受到GC的严重影响。 年轻一代的GC通常不会有问题,因为他们完成了单位数毫秒(或者最多两位数)。 但是老一代的collections品要花费更多的时间,而老旧的collections品大小要达到1G以上。
现在:理论上CMS可以在那里帮助很多,因为它可以同时运行大部分的操作。 然而,随着时间的推移,会出现不能这样做的情况,必须回到“停止世界”收集。 当发生这种情况时(比如说1小时 – 不经常,但仍然太频繁),那么,坚持你的帽子。 这可能需要一分钟或更长的时间。 对于试图限制最大延迟的服务来说,这尤其成问题。 而不是要花费25毫秒来提出请求,现在需要十秒或更长的时间。 为侮辱客户增加伤害将经常超时请求并重试,导致进一步的问题(又名“狗屎风暴”)。
这是G1希望帮助很大的一个领域。 我曾经为一家提供存储和消息调度云服务的大公司工作; 而且我们不能使用CMS,因为尽pipe大部分时间它比平行的品种效果好,但它已经崩溃了。 所以大概一个小时的事情是好的, 然后东西击中扇子…因为服务是基于群集,当一个节点遇到麻烦时,其他人通常遵循(由于GC引起的超时导致其他节点认为节点已经崩溃,导致重新路由)。
我不认为GC对于应用程序来说是一个很大的问题,甚至非集群服务也不太受到影响。 但是越来越多的系统被聚集(特别感谢NoSQL数据存储),并且堆大小也在增长。 OldGen GC与堆大小超线性相关(意味着堆大小加倍,GC时间翻倍,假设实时数据集的大小也加倍)。
Azul的首席技术官Gil Tene对垃圾收集相关的问题有一个很好的概述,他在“ 了解Java垃圾收集和你能做些什么”的演示文稿中回顾了各种解决scheme,本文还有其他细节: http:// http://www.infoq.com/articles/azul_gc_in_detail 。
我们的Zing JVM中的Azul C4垃圾收集器既是并行的,又是并行的,并且对于新老两代都使用相同的GC机制,在这两种情况下同时工作和压缩。 最重要的是,C4没有停止世界的倒退。 所有压缩与正在运行的应用程序同时执行。 我们有客户运行非常大(数百GB),更糟糕的情况下,GC暂停时间<10毫秒,根据应用程序经常less于1-2毫秒。
CMS和G1的问题是,在某些时候Java堆内存必须被压缩,并且这两个垃圾收集器都停止了这个世界/ STW(即暂停应用程序)来执行压缩。 所以,当CMS和G1可以推出STW暂停时,他们不会消除它们。 然而,Azul的C4,完全消除了STW暂停,这就是为什么Zing即使是巨大的堆大小也有如此低的GC暂停。
为了更正以前答案中的陈述,Zing不需要对操作系统进行任何更改。 它像在未经修改的Linux发行版上的任何其他JVM一样运行。
我们已经使用了近两年的G1GC。 它在我们的任务关键型事务处理系统中做得很好,它被certificate是高吞吐量,低暂停,并发性和优化重内存pipe理的很好的支持。
我们正在使用以下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
G1收集器减less了完整收集的影响。 如果您的应用程序已经减less了对完整集合的需求,那么Concurrent地图Sweep收集器就是一样好,根据我的经验,缩短了次要收集时间。
似乎G1开始JDK7u4终于正式支持,请参阅RNK7u4 http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html 。
从我们的testing仍然对于大JVMs调整CMS仍然performance比G1好,但我想它会变得更好。
即使您正在运行CMS,但不会累积终身物件,CMS仍可能导致性能缓慢下降。 这是因为G1本应避免的内存碎片。
关于G1的神话只有付费的支持才是这个神话。 Sun和现在的Oracle已经在JDK页面上阐明了这一点。
最近我已经离开了
使用JDK 1.7.45的服务器上使用4G堆和8核心处理器的CMS到G1GC 。
(JDK 1.8.x G1GC优先于1.7,但由于一些限制,我必须坚持到1.7.45版本)
我已经configuration了以下关键参数,并将所有其他参数保留为默认值。
-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, -XX:ConcGCThreads=n apart from -Xms and -Xmx
如果你想微调这些参数,看看这篇oracle文章。
主要观察:
- 内存使用情况与G1GC一致,与CMS的高低不一样
- 与CMS相比,最大GC暂停时间更短
- 与CMS相比,G1GC在垃圾收集方面花费的时间有点高。
- 与CMS相比,主要collections的数量几乎可以忽略不计
- 与CMS相比,次要收集数量较高
但是我仍然很高兴Max GC的暂停时间比CMS的less。 我已将Max GC暂停时间设置为1.5秒 ,但此值尚未交叉。
相关的SE问题:
Java 7(JDK 7)垃圾收集和文档上的G1
G1 GC应该工作得更好。 但是如果设置-XX:MaxGCPauseMillis过于积极,垃圾收集速度会太慢。 这就是为什么在David Leppik的例子中触发完整的GC。
我最近将Twicsy的一部分移植到了一台128GB内存的新服务器上,并决定使用1.7。 我开始使用与1.6版本相同的内存设置(我有几个实例从500MB到15GB的任何地方运行,现在又增加了一个40GB的新实例),但是这并不能很好地工作。 1.7似乎使用了比1.6更多的堆,并且在头几天遇到了很多问题。 我很幸运有大量的内存工作,并为我的大部分stream程碰到内存,但仍然有一些问题。 我的正常MO是使用一个非常小的最小堆大小为16米,即使是几个千兆字节的最大堆,然后打开增量GC。 这使得停顿保持在最低限度。 但现在不行,我必须把堆的平均最小尺寸增加到我所期望的平均值,而且这个结果非常好。 我仍然有增量GC打开,但我会尝试没有。 现在没有停顿,事情似乎运行得非常快。 所以,我认为这个故事的道德是不要期望你的记忆设置完美地从1.6翻译到1.7。
我刚刚在我们的兵马俑大记忆项目中实施了G1垃圾收集器。 在不同types的收集器上工作时,G1响应时间不到600毫秒,给了我们最好的结果。
您可以在这里findtesting结果(共26个)
希望能帮助到你。
G1使应用程序更加灵活:应用程序的调整将会增加 – 应用程序可以被命名为“软实时”。 这是通过将两种GC运行(小天使和一天中的大天使)replace成大小相同的小天使来完成的。
有关更多详细信息,请参阅: http : //geekroom.de/java/java-expertise-g1-fur-java-7/
我正在使用Java来处理小型和大型的堆,GC和Full GC的问题每天都会出现,因为约束可能比其他更严格:在某些环境中,0.1秒的清除GC或Full GC,杀(CMS,iCMS等),目标是在近乎实时的处理下实现最佳的响应时间(这里的实时处理通常是25毫秒) ,所以,基本上,任何改善GC人机工程学和heutrtique欢迎!
我使用Java 8上的G1GC和Groovy(也是Java 8),并且我正在做各种工作负载,并且G1GC总体上是这样工作的:
-
内存使用率非常低,例如100MB而不是500MB,与默认的Java设置相比
-
响应时间是一致的,非常低
-
在最坏的情况下(没有调优,单线程应用)使用G1GC时,默认设置和G1GC之间的性能降低20%。 考虑到良好的响应时间和低内存使用率,这并不算什么。
-
从multithreading的Tomcat运行时,总体性能提高了30%,内存使用率也低得多,响应时间也大大缩短。
所以总的来说,在使用真正的各种工作负载时,G1GC对于multithreading应用程序来说是非常好的Java 8收集器,甚至对于单线程也有一定的好处。
不build议使用java8 w / G1GC进行浮点计算,并使用类似热点的JVM。 应用程序的完整性和准确性是危险的。
https://bugs.openjdk.java.net/browse/JDK-8148175
JDK-8165766
JDK-8186112