Java垃圾收集器时间限制
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java垃圾收集器时间限制相关的知识,希望对你有一定的参考价值。
情况
我正在为Java竞赛开发一个客户端,每当我收到请求时,我有两秒钟的时间来回复。响应之后的时间直到下一个请求未知。
有时,找到正确的响应需要将近2秒,有时只需几毫秒。问题是当垃圾收集发生在一个较长的计算(也分配了很多对象)中,直到两秒结束时,因此响应发送得太晚而且我被取消资格。
使用详细的gc输出我发现gc通常需要大约0.6秒,即使我试图将其限制在较低的范围内。我也尝试在较短的计算上调用System.gc()
(因为我确信我有大约1.8s,我不需要做任何事情),但它需要1-3s,这也不安全。
我的程序只有很少的长寿命对象,大多数活得短于一秒。
眼镜
我知道程序将始终在具有以下可用资源的同一台机器上运行:
- 64位Ubuntu
- OpenJDK的:8u151的JRE
- Intel® Xeon® Prozessor E5-2620 v4的一个核心
- 1.5 GB的RAM
我目前的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参数以获得更好的结果吗?
答案
以下是您可以尝试减少暂停的事情:
- 尝试G1收集器而不是CMS
- 使用更现实的GC目标。目前的目标每2秒允许200毫秒的世界末日GC时间。增加MaxGCPauseMillis和/或减少GCPauseIntervalMillis。
- 添加另一个核心,以便JVM能够与您的应用程序并行执行GC。
- 减少CMSInitiatingOccupancyFraction,以便在堆不太满时GC触发后台GC线程。
- 降低应用程序生成垃圾的速度。
- 调整您的应用程序算法,以便有更多的空闲时间用于后台GC(在您的单核上)。
另一答案
经过大量的实验,我找到了我需要的标志,现在想要分享这些知识:
-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
以上是关于Java垃圾收集器时间限制的主要内容,如果未能解决你的问题,请参考以下文章
Java虚拟机--垃圾收集器--parallel Scavenge 收集器