2010-05-06 52 views
17

我正在寻找关于如何在低延迟至关重要的环境中最佳调整年轻一代(相对于老一代)的争论。调优垃圾回收以实现低延迟

我自己的测试往往表明,当年轻一代相当大时,延迟是最低的(例如-XX:NewRatio < 3),但我无法调和这种直觉,认为年轻一代越大时间越长应该采取垃圾收集。

该应用程序运行在Linux上64位,JDK 6

内存使用情况是大约长期对象的50Megabytes在启动时(=数据高速缓冲存储器)被加载,并从那里它的只有(许多)非常短的寿命创建对象(平均使用寿命为< 1毫秒)。

一些垃圾回收周期需要10毫秒运行......与应用程序的等待时间,而这又是最大数的毫秒相比,看起来非常不相称。

+0

如果年轻一代很大,那么这是不是意味着半生半活的东西在廉价的年轻一代中消失了,让您的老一代收藏更少? – gustafc 2010-05-06 14:44:19

+1

@elec:我在这里帮不了你......但是你的问题是Java和其“自动化”(看它是如何自动化的)内存管理的根本问题的症状。我越用Java(十年后),我希望自己能够更好地管理内存(而且,我已经使用强制手动内存管理的语言,包括第二代语言(直接进入十六进制代码),几十年前)。在Java世界中,浪费了多少精力和时间来试图理解和“微调”非确定性GC ......对于什么应该是非问题:我想回到C++。 – SyntaxT3rr0r 2010-05-06 15:20:52

+0

@WizardOfOdds - 我同意你的观点......就像我喜欢Java一样,它看起来并不是在需要非常低延迟的环境中使用的正确工具。 – Eleco 2010-05-12 08:48:03

回答

14

对于一个生成大量短命垃圾并且没有多久的应用程序,那么一个可以工作的方法是一个大堆,几乎所有的年轻人和几乎所有的伊甸园和任期都可以存活于YG集合中。比一次。

例如(假设你有一个32位JVM)

  • 3072M堆(XMS和XMN)
  • 128M终身(即XMN2944米)
  • MaxTenuringThreshold = 1
  • SurvivorRatio = 190(即,每个幸存者空间是YG的1/192)
  • TargetSurvivorRatio = 90(即填补这些幸存者尽可能)

您将用于此设置的确切参数取决于您的工作集的稳态大小(即每次收集时有多少活着)。这里的想法显然违背了正常的堆大小规则,但是你没有一个以这种方式行事的应用程序。这个想法是,该应用程序主要是v短命垃圾和一些静态数据,所以设置jvm,以便该静态数据快速生成,然后具有足够大的YG以至于不会收集v,从而最小化暂停的频率。您需要反复旋转旋钮才能找出尺寸适合您的尺寸&这与您在每次收藏中获得的停顿尺寸之间的平衡程度如何。例如,您可能会发现更短但更频繁的YG暂停。

你不说你的应用程序运行了多久,但这里的目标是在应用程序的整个生命周期内完全没有终身收藏。当然这可能是不可能的,但它是值得争取的。

然而,这不仅仅是收集算法,在你的情况下很重要,它是分配内存的地方。 NUMA收集器(仅与吞吐量收集器兼容,并且与UseNUMA切换器一起使用)利用了观察结果,即一个对象通常仅由创建该对象的线程使用,从而相应地分配内存。我不确定它是基于Linux的,但它在Solaris上使用MPO(内存放置优化),some details on one of the GC guys blogs

由于您使用的是64位jvm,因此请确保您使用的是CompressedOops。考虑到对象分配率(可能是某种科学库?)和生命周期,那么你应该考虑对象重用。一个lib这样做的一个例子是javalution StackContext

最后,值得注意的是,GC暂停不是唯一的STW暂停,你可以用6u21 early access构建具有一定的修复到PrintGCApplicationStoppedTime和PrintGCApplicationConcurrentTime开关(即有效印刷运行时间在全球安全点和这些安全点之间的时间)。您可以使用tracesafepointstatistics标志来了解是什么导致它需要一个安全点(也就是说没有任何线程正在执行字节码)。

5

您是否已经启用了更多相关的GC设置,例如选择并发的低暂停收集器算法?

从广义上讲,年轻的,年老的和永久代需要的大小,以满足应用程序的配置文件。如果你有很多短命的物品,但年轻的人太少,很多物品会变得终身,从而迫使整个终身代的更多的主要收藏品。同样,如果年轻人太大,那么终身制就会变得更小,并且可能会迫使主要的终身收藏。

实事求是地讲,我想你会发现,在未成年人度过了与主要收集的时间权衡为您提高年轻一代的尺寸,并且在某些时候是最佳的。

也许是有益的注意,在“大”性能敏感的服务器应用,我认为有必要缩小年轻一代,一般。这是因为这些应用程序应该已经针对内存分配热点进行了分析并进行了优化,所以它们只产生了很少的短期对象。这反过来意味着年轻一代正在占用太多的堆。

所以我想我会先做这个优化,然后看看NewRatio超过8,然后观察-verbose:gc给出的输出,看看GC和Full GC时间是如何折中以及哪里是最优的。

+0

供参考:我搜索了如何启用上述的低暂停收集器,并发现这个看似相关的信息: http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html#1.1.% 20类型%20%链接中的锚点下方的项目#2。它说使用“​​-Xincgc”或“-XX:+ UseConcMarkSweepGC” – 2010-05-17 02:38:43

1

当试图与Java实时应用,垃圾收集调整是必要的,但也有您需要考虑(如JIT编译器,定时器,线程,异步事件处理)等方面。

由于似乎是实时Java的需求,Sun提供了一个Java实时系统规范,并有一个可用的商业实现。你可以找到更多的信息here