Java垃圾收集器时间限制 处境
我正在为Java竞赛开发一个客户端,每当我收到请求时,我都有两秒钟的时间来响应。响应后到下一个请求的时间未知 有时,找到正确的响应需要将近2秒钟,有时只需几毫秒。问题是当垃圾收集发生在一个较长的计算中(它也分配了很多对象)快到两秒钟的时候,因此响应发送得太晚,我被取消资格 通过使用详细的gc输出,我发现gc通常需要0.6秒左右的时间,尽管我试图将其限制得更低。我还尝试在较短的计算中调用Java垃圾收集器时间限制 处境,java,garbage-collection,jvm,Java,Garbage Collection,Jvm,我正在为Java竞赛开发一个客户端,每当我收到请求时,我都有两秒钟的时间来响应。响应后到下一个请求的时间未知 有时,找到正确的响应需要将近2秒钟,有时只需几毫秒。问题是当垃圾收集发生在一个较长的计算中(它也分配了很多对象)快到两秒钟的时候,因此响应发送得太晚,我被取消资格 通过使用详细的gc输出,我发现gc通常需要0.6秒左右的时间,尽管我试图将其限制得更低。我还尝试在较短的计算中调用System.gc()(因为我确信我有大约1.8秒的时间不需要做任何事情),但这需要1-3秒,这也不安全 我的程
System.gc()
(因为我确信我有大约1.8秒的时间不需要做任何事情),但这需要1-3秒,这也不安全
我的程序只有很少的长寿物体,大多数的寿命短于一秒钟
规格
我知道该程序将始终在具有以下可用资源的同一台机器上运行:
- 64位Ubuntu
- openjdk:8u151 jre
- 一个核
- 1.5 GB内存
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时间。增加最大GCPauseMillis和/或减少GCPauseIntervalMillis李>
- 添加另一个核心,以便JVM能够与应用程序并行执行GC
- 减少cmsinitiatingoccuncyfraction,以便在堆不太满时GC触发后台GC线程
- 降低应用程序生成垃圾的速率
- 调整应用程序算法,以便有更多的空闲时间用于后台GC(在单核上)
-在比较我的用例G1和CMS的日志结果后,我确定t CMS暂停时间较低,此外,它仍然支持单线程收集-XX:+useConMarkSweepGC
调用System.gc()时将调用标准gc,而不是完整gc-XX:+explicitgccinvokesconcurrent
老一代与年轻一代的大小比,这是最低值,因为我几乎没有长寿物体-XX:NewRatio=1
-mx800m
减少并修复了内存大小,因此收集将更频繁且花费更少的时间。以吞吐量换取响应能力-ms800m
禁用收集年轻一代的并行化。这是一个破坏者,将GC停止世界时间从0.2-0.5s减少到0.02-0.2s,因为我只有一个内核可用。(不推荐将其与CMS结合使用,并可能在较新的Java版本中删除)-XX:-UseParNewGC
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution
请不要忘记,这些都是针对非常具体的要求进行优化的:只有一个内核可用,大量的年轻垃圾,没有旧的收集,非常低的停止世界暂停
这是一个小备忘,我可以推荐你进一步阅读:据我所知,你不能真正限制垃圾收集。您只能尝试在计算期间保留对所有变量的引用,因为这样GC肯定不会运行(因为所有变量仍然被引用,因此无法释放)。然后,在计算之后,您将取消引用所有内容,以便gc可以运行(并删除一个System.gc(),希望您的垃圾收集得到提示),而不是尝试优化Java垃圾收集(这类似于说您希望弥补哥斯拉),您可能希望尝试关注更大的问题。为什么每当您收到请求时,Java都需要执行GC?GC确实经常发生,但如果您发现了一种模式,那么是您的程序导致了它的发生。你可能想好好看看它背后的原因。如果你试过使用G1垃圾收集,它有更频繁的微循环,几乎是不可见的。gc()只是一个建议,在现代收藏家中,它没有做任何明显的事情。将上面的所有GC参数替换为:--XX:+useg1gc一个不好的方法是调用GC,我的朋友也有同样的问题,即对象管理不好,调用GC或GC做了很多工作。因此,他使用以下参数使GC每小时运行一次:
-java-Dsun.rmi.dgc.client.gcInterval=3600000
,但我认为这也是一种糟糕的方法。看一看你的程序或者这次读一读c++“添加另一个核心”竞赛系统不在我的控制之下。“降低应用程序生成垃圾的速度。”我必须不断地为BFS克隆对象,所以这也不是一个选项。我认为G1是为性能更好的环境而优化的,但到目前为止它看起来不错。我唯一想知道的是,为什么它绝对不记录任何活动,尽管我在其中留下了-verbose:gc-XX:+PrintGCDetails-XX:+PrintGCTimeStamps
。“我必须不断地为BFS克隆对象,所以这也不是一个选项。”-广度优先搜索不需要任何克隆。现在,你的“持续克隆”可能是一种方便的方法。。。。某物但是,如果您重新设计/重新编码y,则很可能可以避免它