当前位置:  开发笔记 > 编程语言 > 正文

生产中的Java G1垃圾收集

如何解决《生产中的JavaG1垃圾收集》经验,为你挑选了8个好方法。

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

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



1> David Leppik..:

我一直在用大量应用程序测试它: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不会为您购买任何东西.



2> Bill K..:

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

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

我会说GC暂停时间将继续改善,而不是恶化,以及将来的版本.

编辑:

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

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

GC仍然是任何人的问题吗?


是的,当您开始处理大堆(> 16GB)时,GC仍然是一个非常大的问题,特别是对于大量的终身产品.
令人烦恼的关于GC的事情是,Azul多年前发明了一种巧妙的GC算法(Azul C4),通过非常巧妙地使用处理器内存硬件,可以轻松应对数百GB而没有任何明显的暂停时间.但是没有人知道这一点,它很快就不会在主要的Java版本中实现,因为它需要操作系统的一些支持.在人们了解算法并对操作系统供应商施加压力之前,操作系统供应商不会做任何事情.见http://www.azulsystems.com/zing/pgc,http://www.managedruntime.org/
是的,GC对服务有问题,因为它们很难提高TP99.9(和更高)的限制.具体而言,"老一代"GC可以是死亡陷阱,除了冻结JVM(和服务)几秒钟之外; 对于通常以一位数(或低两位数)毫秒计数请求的服务,这是有问题的.对于它的价值,这是亚马逊简单队列服务使用的后端存储的实际问题(不能像AWS内部那样涉及大量细节).
@ the-alchemist哇,我已经看过你的评论几次,只是让我感到震惊,你说16 GB !! 虽然我完全相信你是正确的,这可能导致巨大的延迟,但我想检查你是否禁用了所有交换.在大型内存系统上,*任何*交换java都会绝对会破坏你的系统(因为GC非常不符合交换).我相信你已经做到了,但我只想提一下 - 因为它会产生如此巨大的变化.我从未见过有这么多公羊的电脑 - 你有多少钱?32克?

3> StaxMan..:

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

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

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

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



4> Scott Seller..:

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一样运行.


Azul的C4拥有非常独特的技术,其起源于Azul的硬件计算设备(使用专为运行企业Java应用程序而构建的专用处理器),并且已经发展为在运行Linux的常规x86服务器上运行.每个其他企业级垃圾收集器(无论是来自Oracle还是IBM)在某些时候都必须停止世界停顿--Azul C4的独特属性是它永远不会出现这些有问题的STW暂停.如果你很好奇,C4收藏家的发明者发表了一篇关于它是如何工作的论文:http://dl.acm.org/citation.cfm?id = 1064988.
乔治,两个字:专利保护.Dan,当你购买Zing时,你付出的一部分就是让他们的支持人员为你的应用程序调整它 - 包括分配整个系统内存使用量.内核模块本身可以防止写入正在进行垃圾回收的内存块.这是让它"无间歇"的秘诀:如果线程试图写入其中一个块,线程只会暂停,然后只需要足够长的时间来压缩该块.
我只是想知道Azul的C4是如何实现你所说的以及为什么Sun或Oracle无法实现的.是否有一些重大秘密,或者这只是一些权衡?

5> emkays..:

我们已经使用了近两年的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


在Java 8中,您不需要设置-XX:+ UseCompressedOops或-XX:+ DoEscapeAnalysis,booth默认为打开.请参阅:http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

6> Peter Lawrey..:

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



7> 小智..:

似乎G1首先正式支持JDK7u4,请参阅RN for JDK7u4 http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html.

从我们对大型JVM的测试仍然可以调整CMS仍然比G1好,但我想它会变得更好.



8> Ravindra bab..:

最近我已经从

在具有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)垃圾收集和文档

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有