由于Java 7将默认使用新的G1垃圾收集,Java是否能够处理一个数量级更大的堆而不会产生"破坏性"的GC暂停时间?有人在生产中实际实施了G1,你的经历是什么?
公平地说,我唯一一次看到非常长的GC暂停是非常大的堆,远远超过工作站.澄清我的问题; G1将打开数百GB的网关?TB?
我一直在用大量应用程序测试它: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不会为您购买任何东西.
听起来G1的要点是具有较小的暂停时间,甚至可以指定最大暂停时间目标.
垃圾收集不仅仅是一个简单的"嘿,它已经完整,让我们一次性移动所有东西并重新开始"处理 - 它是非常复杂的,多层次的,后台线程系统.它可以在后台完成大部分维护而不会暂停,它还可以在运行时使用系统预期模式的知识来帮助 - 比如假设大多数对象在创建后就死了,等等.
我会说GC暂停时间将继续改善,而不是恶化,以及将来的版本.
编辑:
在重新阅读时,我发现我每天都使用Java - Eclipse,Azureus和我开发的应用程序,自从我看到暂停以来,这是一段很长的时间.不是一个重要的停顿,但我的意思是任何停顿.
当我右键单击Windows资源管理器或(偶尔)我连接某些USB硬件时,我已经看到了暂停,但是使用Java ---根本没有.
GC仍然是任何人的问题吗?
虽然我没有在生产中测试G1,但我认为我会评论说,如果没有"大量"堆积的情况,GC已经存在问题.具体而言,只有2或4场演出的服务可能会受到GC的严重影响.年轻代GC通常没有问题,因为它们以一位数毫秒(或最多两位数)完成.但老一代的收藏品问题更多,因为他们需要花费数秒钟才能使用1 gig或更高的旧版本.
现在:理论上CMS在那里可以提供很多帮助,因为它可以同时运行大部分操作.然而,随着时间的推移,将会出现无法做到这一点并且不得不回到"停止世界"收集的情况.当发生这种情况时(比如1小时之后 - 不经常,但仍然经常发生),好吧,坚持你的帽子.可能需要一分钟或更长时间.对于试图限制最大延迟的服务而言,这尤其成问题; 而不是采用25毫秒来提供请求,现在需要10秒或更长时间.为了给侮辱客户增加伤害,通常会超时请求并重试,从而导致进一步的问题(又名"狗屎风暴").
这是G1希望帮助很多的一个领域.我曾在一家大公司工作,为存储和消息调度提供云服务; 我们不能使用CMS,因为虽然它大部分时间比并行品种更好,但它有这些崩溃.所以大约一个小时的事情很好; 然后东西击中了风扇......并且因为服务是基于集群的,当一个节点遇到麻烦时,其他节点通常会跟随(因为GC引起的超时导致其他节点认为节点已经崩溃,导致重新路由).
我不认为GC对应用程序来说是一个很大的问题,甚至非集群服务也可能不那么受影响.但是越来越多的系统被集群化(特别是感谢NoSQL数据存储),并且堆大小正在增长.OldGen GC与堆大小超线性相关(意味着,如果实时数据集的大小也增加一倍,则堆大小加倍会使GC时间增加一倍以上).
Azul的首席技术官Gil Tene对与垃圾收集相关的问题进行了很好的概述,并对他的" 了解Java垃圾收集"和"你能做些什么"介绍中的各种解决方案进行了回顾,本文还有其他细节:http:// www.infoq.com/articles/azul_gc_in_detail.
我们的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一样运行.
我们已经使用了近两年的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
G1收集器减少了完整收藏的影响.如果你有一个应用程序,你已经减少了对完整集合的需求,那么Concurrent map Sweep collector也同样好,根据我的经验,缩短了收集时间.
似乎G1首先正式支持JDK7u4,请参阅RN for JDK7u4 http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html.
从我们对大型JVM的测试仍然可以调整CMS仍然比G1好,但我想它会变得更好.
最近我已经从
在具有JDK 1.7.45的服务器上,使用4G堆和8核处理器的CMS到G1GC。
(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文章。
关键观察:
内存使用情况与G1GC一致,与CMS的高低不同
与CMS相比,最大GC暂停时间更少
与CMS相比,G1GC在垃圾收集上花费的时间很少。
与CMS相比,主要收藏的数量几乎可以忽略不计
与CMS相比,次要收藏的数量更高
但是,我仍然很高兴Max GC的暂停时间少于CMS的时间。我已将“最大GC暂停时间”设置为1.5秒,并且尚未超过该值。
相关的SE问题:
G1上的Java 7(JDK 7)垃圾收集和文档