JVM和GC调优-无Full GC的理论

13

我有一个大型的应用程序,包含两种类型的对象:长期存在的(缓存)和短期存在的(请求 - 处理 - 响应)。理论上,对于这种类型的应用程序,我认为可以配置Young和Old空间,以便Old空间消耗是恒定的,从而不会发生Full GC。

我已更改newSize-maxNewSize参数,但旧堆继续上升,直到发生Full GC。每次Full GC后,消耗量下降到20%(缓存占用20%)。由于某些原因,我的对象进入了Old空间。我有两个嫌疑对象为什么要移动到Old空间:

  • 根据这篇文章:http://chaoticjava.com/posts/gc-tips-and-memory-leaks/,如果您分配了大对象,它们会直接进入Old空间。这是真的吗?如果是,是否有JVM选项参数可以设置Young空间的对象大小阈值?

  • 如果我正确地理解了该过程,则在将对象移动到Old部分之前,对象会在To-From存活段之间切换。是否有参数可以设置在移动到Old空间之前要进行多少次To-From切换?

还有其他提示吗?

谢谢, Amar

4个回答

5

听起来你的幸存者空间不够大。需要将它们扩大到足够大,以便无需收集任何对象。一个对象只会在幸存者空间中切换一次。

如果你正在分配大型对象,可以为它们使用对象池来避免需要垃圾回收。你是否考虑过为请求/处理/响应数据使用对象池?例如,可以使用ThreadLocal来实现一个简单的对象池。

你尝试过G1收集器吗?它旨在逐步收集所有内存并减少完全GC的大冲击。


5
你确定老一代的增长只是缓存对象吗?除非你的缓存是固定且永不更改的,否则你将不断地向其中添加内容。当已经进入老一代的对象从缓存中过期后,它们会一直停留在内存中,直到下一个完整的GC。
我使用并发标记扫描收集器取得了更好的效果,完全消除了完整GC的长时间暂停。这需要一些调整,并且可能因应用程序而异。以下是我们用于运行24GB 64位JVM的配置,每秒服务100多个页面请求和大型缓存时,其子秒GC暂停:
-Xms24g -Xmx24g -XX:+UseCompressedOops -XX:NewRatio=4 -XX:SurvivorRatio=8    
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+DisableExplicitGC  
-XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled  
-XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=68

WhiteFang34,如果我想尝试你的参数,是否需要将-Dsun.rmi.dgc.client.gcInterval=3600000和-Dsun.rmi.dgc.server.gcInterval=3600000这些选项从我的JVM参数中移除? - Eazy
@Yoldar-Zi,你可以保留那些RMI选项。 - WhiteFang34

2
有没有参数可以设置在移动到老年代之前,在“From”和“To”幸存者空间之间切换的次数?
是的,-XX:MaxTenuringThreshold
此开关确定对象在跳转到旧一代之前在“From”和“To”幸存者空间之间跳转的次数。对于Java 6,最大值为15,而对于早期JDK,则为31。并行收集器的默认值为15,CMS收集器的默认值为4
根据Sun JVM GC文档,
使用-XX:MaxTenuringThreshold=0将一个在年轻代收集中幸存下来的对象立即移动到旧年代。
由于您想要执行与此相反的操作,如果您尚未设置此值,则默认值足以决定对象是否需要进入旧年代,前提是,如@Peter所说,幸存者足够大以容纳这些对象。
您的SurvivorRatio设置为多少?您的总堆大小是多少?

0

对象生命周期特征在这里起着关键作用。重要的调整开关是幸存者空间大小、终身阈值和年轻代大小。战略上,我们希望对象年轻就死亡,因此如果在较小的集合之间有足够的间隔,许多对象将在年轻代中死亡。此外,我们可以配置终身阈值,使对象在所需的集合数量内保留在幸存者空间中。

由于我们在幸存者空间中保留了大量活动对象,并将它们从一个空间复制到另一个空间进行许多次轻微的GC,这增加了轻微GC的成本。

保持较大的年轻代自然会增加连续次序列集合之间的间隔,并为对象提供更长的死亡时间。

通过尝试使用这些变量来平衡,以便降低对象晋升到旧一代的程度,并考虑可接受的年轻一代暂停时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接