我正在使用一个提供REST API的应用程序。它只处理GET请求,即使是最重的请求也通常需要100毫秒。
最近我们开始遇到一个问题,时不时地堆会被填满,全GC需要很长时间,这真的影响到了我们的客户。
一些额外的发现:
- 我们启用了JVM标志-XX:+PrintTenuringDistribution,根据此标志输出,新的tenuring阈值在应用程序启动后几分钟内变为1,即使没有显着负载。 - 当应用程序消耗了几乎所有允许的内存时,我们进行了内存转储,并根据MAT分析器的统计数据,几乎所有在转储中的对象都是不可达的(因此,我无法理解为什么它们会被提升到老年代)。 - Survivor空间几乎没有使用。看起来新对象直接从Eden空间晋升到Old Gen。 - 每10-20秒钟进行一次Minor GC。 - 增加Eden / Survivor空间没有帮助解决问题(tenuring阈值仍为1)。
因此,请问:
- 为什么tenuring阈值会这么快变为1?[已解决] - 还可以采取哪些附加步骤以避免将新对象提升到旧代?
以下是应用程序的一些参数:
- 堆大小 - 5GB - 每秒并发请求数量 - 高达50个 - 每个请求最多消耗1-2MB(有些请求会消耗12 MB的堆内存) - 应用程序同时使用Parallel GC进行Old和young geerations。 - JDK 1.7
请让我知道是否需要其他信息。
最近我们开始遇到一个问题,时不时地堆会被填满,全GC需要很长时间,这真的影响到了我们的客户。
一些额外的发现:
- 我们启用了JVM标志-XX:+PrintTenuringDistribution,根据此标志输出,新的tenuring阈值在应用程序启动后几分钟内变为1,即使没有显着负载。 - 当应用程序消耗了几乎所有允许的内存时,我们进行了内存转储,并根据MAT分析器的统计数据,几乎所有在转储中的对象都是不可达的(因此,我无法理解为什么它们会被提升到老年代)。 - Survivor空间几乎没有使用。看起来新对象直接从Eden空间晋升到Old Gen。 - 每10-20秒钟进行一次Minor GC。 - 增加Eden / Survivor空间没有帮助解决问题(tenuring阈值仍为1)。
因此,请问:
- 为什么tenuring阈值会这么快变为1?[已解决] - 还可以采取哪些附加步骤以避免将新对象提升到旧代?
以下是应用程序的一些参数:
- 堆大小 - 5GB - 每秒并发请求数量 - 高达50个 - 每个请求最多消耗1-2MB(有些请求会消耗12 MB的堆内存) - 应用程序同时使用Parallel GC进行Old和young geerations。 - JDK 1.7
请让我知道是否需要其他信息。
-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),启动性能测试后,老年代仍会增长:
如果我启动GC,它可以成功清理内存
如果我进行堆转储,则Mat Analyzer(或Yourkit)再次显示80%的对象无法访问