调整垃圾收集以实现低延迟

Ele*_*eco 19 java garbage-collection

我正在寻找关于如何在低延迟至关重要的环境中最好地确定年轻一代(相对于老一代)的规模的论据.

我自己的测试往往表明延迟最低,当年轻的一代是相当大(例如-XX:NewRatio <3),但是我不能与直觉,较大的年轻一代更多的时间,应该采取垃圾调和这搜集.

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

内存使用量大约是50兆字节的启动时加载的长寿命对象(=数据缓存),并且从那里开始只创建(很多)非常短暂的对象(平均寿命<1毫秒).

一些垃圾收集周期需要超过10毫秒才能运行...与app延迟相比看起来真的不成比例,而app延迟又是几毫秒.

Mat*_*att 14

对于一个产生大量短寿命垃圾并且没有长寿的应用程序,一种可以工作的方法是一大堆几乎所有的年轻人和几乎所有的伊甸园和任期在YG集合中不止一次存活的任何东西.

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

  • 3072M堆(Xms和Xmn)
  • 128M终身(即Xmn 2944m)
  • MaxTenuringThreshold = 1
  • SurvivorRatio = 190(即每个幸存者空间是YG的1/192)
  • TargetSurvivorRatio = 90(即尽可能多地填补幸存者)

您将用于此设置的确切参数取决于工作集的稳态大小(即每次收集时的活动量).这里的想法显然违反了正常的堆大小规则,但是你没有一个以这种方式运行的应用程序.我们的想法是,应用程序主要是v短暂的垃圾和一些静态数据,所以设置jvm以便静态数据快速进入终身,然后有一个足够大的YG,以便不经常收集,从而最大限度地减少暂停的频率.你需要反复旋转旋钮来找出适合你的大小,以及如何平衡你每次收集的暂停大小.您可能会发现更短但更频繁的YG暂停是可以实现的.

你没有说你的应用程序运行了多长时间,但这里的目标是在应用程序的生命周期内根本没有终身收藏.当然这可能是不可能的,但值得瞄准.

然而,在你的情况下,它不仅仅是收集算法,它是分配内存的地方.NUMA收集器(仅与吞吐量收集器兼容并使用UseNUMA交换机激活)利用观察对象通常纯粹由创建它的线程使用,从而相应地分配内存.我不确定它是基于Linux的,但它在Solaris上使用MPO(内存放置优化),其中一个GC人员博客的一些细节

由于您使用的是64位jvm,因此请确保您使用的是CompressedOops.

鉴于对象分配率(可能是某种科学库?)和生命周期,你应该考虑对象重用.执行此操作的lib的一个示例是javalution StackContext

最后值得注意的是,GC暂停不是唯一的STW暂停,你可以运行6u21早期访问构建,它对PrintGCApplicationStoppedTime和PrintGCApplicationConcurrentTime开关有一些修复(有效地在全局安全点打印时间和这些安全点之间的时间).您可以使用tracesafepointstatistics标志来了解导致它需要安全点的原因(也就是说任何线程都没有执行字节代码).


Sea*_*wen 5

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

从广义上讲,年轻,终身和永久的年龄需要根据您的应用程序的配置进行调整.如果你有许多短暂的物品,但是年轻的物体太小,很多物体都会变成终身,迫使整个终身一代的主要藏品更加频繁.同样,如果年轻人太大,那么终身职位必然会变小,并且可能会迫使经常招聘大部分人.

实际上,我认为你会发现,当你增加年轻一代的规模时,在小型系列和主要系列中花费的时间会有所不同,并且在某些时候是最佳的.

也许有用的是注意到在"大"性能敏感的服务器应用程序中,我发现有必要缩小年轻一代.这是因为这些应用程序应该已经为内存分配热点进行了分析并进行了优化,因此它们只能生成很少的短期对象.这反过来意味着年轻一代正在占据过多的钱.

所以我想我首先要进行优化,然后再看看NewRatio超过8,然后观察-verbose:gc给出的输出,看看GC和Full GC时间是如何交易的,以及它是最优的.