Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java垃圾收集器时间限制 处境_Java_Garbage Collection_Jvm - Fatal编程技术网

Java垃圾收集器时间限制 处境

Java垃圾收集器时间限制 处境,java,garbage-collection,jvm,Java,Garbage Collection,Jvm,我正在为Java竞赛开发一个客户端,每当我收到请求时,我都有两秒钟的时间来响应。响应后到下一个请求的时间未知 有时,找到正确的响应需要将近2秒钟,有时只需几毫秒。问题是当垃圾收集发生在一个较长的计算中(它也分配了很多对象)快到两秒钟的时候,因此响应发送得太晚,我被取消资格 通过使用详细的gc输出,我发现gc通常需要0.6秒左右的时间,尽管我试图将其限制得更低。我还尝试在较短的计算中调用System.gc()(因为我确信我有大约1.8秒的时间不需要做任何事情),但这需要1-3秒,这也不安全 我的程

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

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

通过使用详细的gc输出,我发现gc通常需要0.6秒左右的时间,尽管我试图将其限制得更低。我还尝试在较短的计算中调用
System.gc()
(因为我确信我有大约1.8秒的时间不需要做任何事情),但这需要1-3秒,这也不安全

我的程序只有很少的长寿物体,大多数的寿命短于一秒钟

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

  • 64位Ubuntu
  • openjdk:8u151 jre
  • 一个核
  • 1.5 GB内存
我当前的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时间。增加最大GCPauseMillis和/或减少GCPauseIntervalMillis
  • 添加另一个核心,以便JVM能够与应用程序并行执行GC
  • 减少cmsinitiatingoccuncyfraction,以便在堆不太满时GC触发后台GC线程
  • 降低应用程序生成垃圾的速率
  • 调整应用程序算法,以便有更多的空闲时间用于后台GC(在单核上)

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

  • -XX:+useConMarkSweepGC
    -在比较我的用例G1和CMS的日志结果后,我确定t CMS暂停时间较低,此外,它仍然支持单线程收集
  • -XX:+explicitgccinvokesconcurrent
    调用System.gc()时将调用标准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
请不要忘记,这些都是针对非常具体的要求进行优化的:只有一个内核可用,大量的年轻垃圾,没有旧的收集,非常低的停止世界暂停


这是一个小备忘,我可以推荐你进一步阅读:

据我所知,你不能真正限制垃圾收集。您只能尝试在计算期间保留对所有变量的引用,因为这样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,则很可能可以避免它