由于 Java 7 将默认使用新的 G1 垃圾收集,Java 是否能够处理更大数量级的堆,而无需假定“破坏性”的 GC 暂停时间?有没有人真正在生产中实现过 G1,你的经验是什么?
公平地说,我唯一一次看到非常长的 GC 暂停是在非常大的堆上,比工作站要多得多。澄清我的问题;G1 会为数百 GB 的堆打开网关吗?结核病?
由于 Java 7 将默认使用新的 G1 垃圾收集,Java 是否能够处理更大数量级的堆,而无需假定“破坏性”的 GC 暂停时间?有没有人真正在生产中实现过 G1,你的经验是什么?
公平地说,我唯一一次看到非常长的 GC 暂停是在非常大的堆上,比工作站要多得多。澄清我的问题;G1 会为数百 GB 的堆打开网关吗?结核病?
我一直在用一个繁重的应用程序对其进行测试:为堆分配 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。如果 Oracle 继续调整它,我怀疑 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 的 CTO 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 收集器减少了完整收集的影响。如果您的应用程序已经减少了对完整收集的需求,那么并发地图扫描收集器同样出色,并且根据我的经验,次要收集时间更短。
最近我从
CMS 到 G1GC,在 JDK 1.7.45 的服务器上具有 4G 堆和 8 核处理器。
(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文章。
主要意见:
但我仍然很高兴 Max GC 暂停时间少于 CMS。我已将 Max GC pause time 设置为1.5 秒,但尚未超过此值。
相关的 SE 问题:
看来G1开始JDK7u4终于得到官方支持了,看JDK7u4的RN http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html。
从我们对大型 JVM 的测试来看,调整后的 CMS 仍然比 G1 表现得更好,但我想它会变得更好。
CMS 可能会导致性能缓慢下降,即使您在没有累积永久对象的情况下运行它也是如此。这是因为 G1 应该避免的内存碎片。
关于 G1 只有付费支持才能获得的神话只是一个神话。Sun 和现在的 Oracle 已经在 JDK 页面上澄清了这一点。
G1 GC 应该工作得更好。但是如果设置 -XX:MaxGCPauseMillis 过于激进,垃圾收集会太慢。这就是为什么在 David Leppik 的示例中触发了完整的 GC。
我刚刚在我们的 Terracotta Big Memory 项目中实现了 G1 垃圾收集器。在处理不同类型的收集器时,G1 以不到 600 毫秒的响应时间为我们提供了最好的结果。
您可以在此处找到测试结果(共 26 个)
希望能帮助到你。
我最近将 Twicsy 的一部分迁移到具有 128GB RAM 的新服务器并决定使用 1.7。我开始使用与 1.6 相同的内存设置(我有几个实例在运行各种事情,从 500mb 到 15GB 的堆,现在是一个 40GB 的新实例),但效果并不好。 . 1.7 似乎比 1.6 使用了更多的堆,在最初的几天里我遇到了很多问题。幸运的是,我有足够的 RAM 可以使用,并且为我的大多数进程增加了 RAM,但仍然遇到了一些问题。我的常规 MO 是使用 16m 的非常小的最小堆大小,即使最大堆为几 GB,然后打开增量 GC。这将停顿保持在最低限度。但这现在不起作用,我不得不将最小大小增加到我期望在堆中平均使用的大小,效果很好。我仍然打开了增量 GC,但我会在没有的情况下尝试它。现在没有任何停顿,事情似乎运行得非常快。所以,我认为这个故事的寓意是不要指望你的记忆设置能完美地从 1.6 转换到 1.7。
G1 使应用程序更加敏捷:应用程序的延迟将增加 - 该应用程序可以命名为“软实时”。这是通过将两种类型的 GC 运行(小型次要运行和 Tenured Gen 上的大型运行)替换为相同大小的小型运行来完成的。
有关更多详细信息,请查看: http: //geekroom.de/java/java-expertise-g1-fur-java-7/
我正在使用 Java,用于小型和大型堆,并且每天都会出现 GC 和 Full GC 的问题,因为约束可能比其他的更严格:在某些环境中,0.1 秒的 scavenger GC 或 Full GC,杀死简单的功能,并且具有细粒度的配置和功能很重要(CMS,iCMS,其他......目标是通过近乎实时的处理获得最佳的响应时间(这里的实时处理通常是 25 毫秒) ,所以,基本上,欢迎对 GC 人机工程学和启发式进行任何改进!
我在 Java 8 和 Groovy(也是 Java 8)上使用 G1GC,我正在做各种工作负载,总体上 G1GC 的工作方式如下:
与默认 Java 设置相比,内存使用率非常低,例如 100MB 而不是 500MB
响应时间一致且非常低
在最坏的情况下使用 G1GC(没有调整,单线程应用程序)时,默认设置和 G1GC 之间的性能降低了 20%。考虑到良好的响应时间和低内存使用率并不多。
从多线程的 Tomcat 运行时,整体性能提高了 30%,内存使用率降低了很多,响应时间也降低了很多。
所以总的来说,当使用各种工作负载时,G1GC 对于 Java 8 的多线程应用程序来说是非常好的收集器,即使对于单线程应用程序也有一些好处。
不建议使用带有 G1GC 的 java8 来使用类似热点的 JVM 进行浮点计算。这对应用程序的完整性和准确性很危险。
https://bugs.openjdk.java.net/browse/JDK-8148175
JDK-8165766
JDK-8186112