物体不断被提升为老一代

时间:2016-06-16 22:00:57

标签: java memory garbage-collection jvm heap-memory

我正在使用提供REST API的应用程序。它仅适用于GET请求,通常花费最多100毫秒来处理最繁重的请求。

最近我们开始面临一个问题,即堆不时被填满,而且完整的GC需要花费大量时间,这确实会影响我们的客户。

  • 堆大小 - 5GB
  • 每秒并发请求数 - 最多50个
  • 每个请求最多消耗1-2MB(消耗12 MB堆的请求很少)
  • 应用程序使用Paralel GC进行旧的和年轻的geerations。
  • JDK 1.7

从我的角度来看,这个应用程序应该在工作一开始就促进Old Gen中的一些对象,之后所有新对象都应该从Eden或Survivor空间中删除。因此,完整的GC绝不会来。然而,有些物品会被提升为Old Gen,这对我来说真的很困惑。

其他一些发现:

  • 我们启用了JVM标志-XX:+ PrintTenuringDistribution,并且根据此标志输出,在应用程序启动后的几分钟内,新的终身临界值变为等于1,即使没有明显的负载。
  • 当应用程序使用所有允许的内存时,我们进行了内存转储,根据MAT分析器统计,几乎所有转储的对象都无法访问(因此,我无法理解为什么它们会被提升为Old Gen)
  • 几乎不使用幸存者空间。看起来新对象从Eden space升级为Old gen。
  • 次要GC每次约10-20秒。
  • 增加伊甸园/幸存者空间并没有帮助解决问题(暂停阈值仍为1)

那么,请你指点一下:

  • 由于什么原因,终身临界值变得如此之快?[已解决]
  • 我可以采取哪些其他措施来避免将新对象推广到旧版本?

如果您需要其他信息,请与我们联系。

修改

JVM参数(已更新):

-XX:MaxPermSize=512m -Xmx7g -Xmn4g -verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintTenuringDistribution

申请日志:

Desired survivor size 520617984 bytes, new threshold 15 (max 15)
 [PSYoungGen: 3235245K->231763K(3665920K)] 3942774K->939308K(4760064K), 0.0905430 secs] [Times: user=0.31 sys=0.00, real=0.09 secs] 
603.561: [GC
Desired survivor size 521142272 bytes, new threshold 15 (max 15)
 [PSYoungGen: 3369299K->330881K(3684864K)] 4076844K->1038442K(4779008K), 0.1343473 secs] [Times: user=0.51 sys=0.00, real=0.13 secs] 
606.347: [GC
Desired survivor size 506462208 bytes, new threshold 15 (max 15)
 [PSYoungGen: 3507329K->215655K(3685376K)] 4214890K->923233K(4779520K), 0.0925060 secs] [Times: user=0.36 sys=0.00, real=0.09 secs] 
609.084: [GC
Desired survivor size 492306432 bytes, new threshold 15 (max 15)
 [PSYoungGen: 3392103K->213344K(3713536K)] 4099681K->920945K(4807680K), 0.0802729 secs] [Times: user=0.30 sys=0.00, real=0.08 secs] 

重要细节

即使我只用1个线程(每个请求消耗~10 MB)开始性能测试,Old Gen仍在不断增长: Old Gen with 1 thread perf test

如果我启动GC它会成功清理内存

如果我进行堆转储Mat Analyzer(或Yourkit)再次显示80%的对象无法访问

1 个答案:

答案 0 :(得分:1)

如果您的任期阈值迅速降至1,则听起来您正在使用其他参数导致此问题。除了日志记录选项和最大堆之外,我会尝试删除所有其他调整参数,并且只有在您确定它们真正有用时才添加每个参数。你设置的越多,你获得一些奇怪行为的可能性就越大。您可以尝试强制终止阈值,但我怀疑这只会隐藏您的问题。

  

所需幸存者大小341835776字节,新阈值1(最多15)

为了增加幸存者的数量以避免完全幸存者触发一个完整的GC,幸存者大小或仅仅一代人正在使用整个年轻空间。

我会尝试让年轻一代更大。你需要一个至少你的幸存者空间的伊甸园,所以你的年轻人应该至少1 GB,理想情况下要大几倍。我会尝试4 GB年轻或2 Gb,具体取决于你有多少空间。 e.g。

-Xmn2g -Xmx5g

-Xmn4g -Xmx7g

如果你有足够的内存,例如64 GB或更多,我会尝试更大像

 -Xmn24g -Xmx32g

并减少年轻空间,如果它似乎没有帮助。