Java垃圾收集器时间限制

问题描述 投票:3回答:2

情况

我正在为Java竞赛开发一个客户端,每当我收到请求时,我有两秒钟的时间来回复。响应之后的时间直到下一个请求未知。

有时,找到正确的响应需要将近2秒,有时只需几毫秒。问题是当垃圾收集发生在一个较长的计算(也分配了很多对象)中,直到两秒结束时,因此响应发送得太晚而且我被取消资格。

使用详细的gc输出我发现gc通常需要大约0.6秒,即使我试图将其限制在较低的范围内。我也尝试在较短的计算上调用System.gc()(因为我确信我有大约1.8s,我不需要做任何事情),但它需要1-3s,这也不安全。

我的程序只有很少的长寿命对象,大多数活得短于一秒。

眼镜

我知道程序将始终在具有以下可用资源的同一台机器上运行:

我目前的jvm参数:

java -Dfile.encoding=UTF-8 \
  -XX:MaxGCPauseMillis=200 \
  -XX:GCPauseIntervalMillis=2050 \
  -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled \
  -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 \
  -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark \
  -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

思路

  • 我能以某种方式告诉gc它现在应该收集一些垃圾,但只有1.5秒左右?
  • 是否有一个System.gc()等效,只适用于年轻的物体,不检查终身一代?
  • 可以优化jvm参数以获得更好的结果吗?
java garbage-collection jvm
2个回答
2
投票

以下是您可以尝试减少暂停的事情:

  • 尝试G1收集器而不是CMS
  • 使用更现实的GC目标。目前的目标每2秒允许200毫秒的世界末日GC时间。增加MaxGCPauseMillis和/或减少GCPauseIntervalMillis。
  • 添加另一个核心,以便JVM能够与您的应用程序并行执行GC。
  • 减少CMSInitiatingOccupancyFraction,以便在堆不太满时GC触发后台GC线程。
  • 降低应用程序生成垃圾的速度。
  • 调整您的应用程序算法,以便有更多的空闲时间用于后台GC(在您的单核上)。

0
投票

经过大量的实验,我找到了我需要的标志,现在想要分享这些知识:

  • -XX:+UseConcMarkSweepGC - 在比较我的用例的G1和CMS的日志结果后,我确定CMS暂停时间较短,此外它仍然支持单线程集合
  • -XX:+ExplicitGCInvokesConcurrent在调用System.gc()时,不会调用Full GC,而是调用标准GC。
  • -XX:NewRatio=1老一代与年轻一代的大小比例,这是我生命对象很少的最低值
  • -mx800m -ms800m减少并修复了内存大小,因此集合将更频繁地发生并且花费更少的时间。交易吞吐量以响应。
  • -XX:-UseParNewGC禁用并行化以收集年轻一代。这是一个交易破坏者,并将GC停止世界时间从0.2-0.5s减少到0.02-0.2s,因为我只有一个核心可用。 (不推荐将此与CMS结合使用,并且可能会在较新的Java版本中删除)

使用这些参数,我可以减少GC暂停时间,从0.4s到3s之间变化,一直小于0.2秒。为了完整起见,这些标志对于调试最有用:

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution

请不要忘记,这些都针对非常具体的要求进行了优化:Onle one core available,很多年轻垃圾,没有旧收藏,非常低的世界停留

这是一个我可以推荐进一步阅读的小作弊表:http://blog.ragozin.info/2016/10/hotspot-jvm-garbage-collection-options.html

© www.soinside.com 2019 - 2024. All rights reserved.