为什么JVM(JDK 1.6)不使用幸存者空间而是触发FGC

时间:2015-02-03 03:29:48

标签: java garbage-collection jvm

我的app服务器出现这种反复出现的问题 - 在某些时候,JVM停止使用幸存者空间,并增加了FGC的数量。

JVM选项为:-XX:+UnlockDiagnosticVMOptions -XX:ParallelGCThreads=4 -XX:PermSize=256m -XX:MaxPermSize=256m -XX:MaxNewSize=1700m -XX:NewSize=1700m -XX:NewRatio=2 -XX:SurvivorRatio=4 -XX:+UseParallelGC -Xms2500m -Xmx2500m -server(32位模式)

我没有jstat -gc输出(1秒间隔)

正常工作:离开伊甸园,YGC触发,幸存者转移到S0。

S0C      S1C      S0U       S1U     EC        EU          OC         OU        PC       PU       YGC    YGCT      FGC   FGCT      GCT
290112.0 290112.0 105412.4 0.0      1160576.0 1084253.6   819200.0   796831.2  262144.0 106050.3 179203 66406.885 20428 31661.316 98068.201
290112.0 290112.0 105412.4 1173.7   1160576.0 1160575.6   819200.0   797324.0  262144.0 106050.3 179204 66406.885 20428 31661.316 98068.201
290112.0 290112.0  0.0     208205.7 1160576.0 86186.5     819200.0   798858.0  262144.0 106050.3 179204 66407.281 20428 31661.316 98068.596

异常工作:跑出伊甸园,触发FGC

S0C      S1C       S0U    S1U   EC        EU         OC         OU        PC       PU       YGC    YGCT      FGC   FGCT      GCT
290112.0 290112.0  0.0    0.0   1160576.0 927072.3   819200.0   765967.3  262144.0 106206.4 158462 63362.970 26039 40083.545 103446.515
290112.0 290112.0  0.0    0.0   1160576.0 993774.1   819200.0   765967.3  262144.0 106206.4 158462 63362.970 26039 40083.545 103446.515
290112.0 290112.0  0.0    0.0   1160576.0 1160576.0  819200.0   765967.3  262144.0 106206.4 158462 63362.970 26040 40083.545 103446.515
290112.0 290112.0  0.0    0.0   1160576.0 1160576.0  819200.0   765967.3  262144.0 106206.4 158462 63362.970 26040 40083.545 103446.515
290112.0 290112.0  0.0    0.0   1160576.0 133591.1   819200.0   767707.1  262144.0 106206.4 158462 63362.970 26040 40085.194 103448.164

这是同一步骤,但是使用-gccause:

S0     S1    E      O      P     YGC     YGCT     FGC   FGCT      GCT        LGCC                 GCC                 
0.00   0.00  83.01  97.22  40.51 158514 63384.780 26045 40092.461 103477.241 unknown GCCause      No GC               
0.00   0.00 100.00  97.22  40.51 158514 63384.780 26046 40092.461 103477.241 Allocation Failure   unknown GCCause     
0.00   0.00 100.00  97.22  40.51 158514 63384.780 26046 40092.461 103477.241 Allocation Failure   unknown GCCause     

(对于"正常工作"情况,列出的GC原因相同,"分配失败")

另一个"有趣"关于这一点的事实,因为一直坚持做FGC的VM实际上可以在没有任何干预的情况下恢复到正常行为(但是等到它做到这一点是个坏主意,因为自从2-3秒FGC开始频繁的基础是响应时间杀手。)

两个进程运行的时间大约相同(~27天),具有相同的堆配置。任何线索,或只是挖掘的地方,将不胜感激。

版本:

$ /home/mispot/jdk1.6.0_45/bin/java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) Server VM (build 20.45-b01, mixed mode)
$ uname -a
Linux ip-10-16-30-13 3.14.26-24.46.amzn1.x86_64 #1 SMP Wed Dec 10 10:02:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

P.S。是的,有一个计划继续升级到JDK 1.8,但这样的升级需要时间,我想知道这里是否有一个低悬的水果值得追求。

2 个答案:

答案 0 :(得分:1)

这只是一个分析,我怀疑它会解决你的问题,但这会给你一些见解:))

我建议你的VM标志没什么变化

-XX:NewSize=1700m -XX:NewRatio=2 -XX:+UseParallelGC

NewSize和NewRatio在你的情况下相互矛盾,因为NewRatio是2,旧的gen将是堆的2/3,新的gen将是堆的1/3。由于堆大小为2500m,你的新gen将是〜833m,但你也使用NewSize标志,所以这将覆盖NewRatio,正如你在jstat输出中看到的那样,new gen是290112k + 290112k + 1160576k ~= 1740800k。< / p>

  • 删除NewRatio,因为它在这种情况下无效
  • 除了UseParallelGC之外还使用-XX:+UseParallelOldGC,因为后者只使用您配置的4个线程并行进行年轻的gen收集,旧的gen仍然是串行的

使用以下标志获取有关GC的更多信息

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
-XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution
-Xloggc:logs-dir-path/gc.log

提出您的问题,当Eden已满并且GC之后的任何活动对象被移动到幸存者空间(S0和S1)时,将发生Young GC。通常它们在它们使用旧生成之前保留少量GC的对象,但是如果它们试图在S0 / S1中保留的对象大于这些空间的大小,那么则对象直接移入到旧生成< / strong>即可。所以没有使用幸存者空间,最终旧的gen将会填满,并且会发生一个只使用1个线程的Full GC,因为只有UseParallelGC

此外,您已将NewSize明确设置为1700m,因此旧尺寸将保持800m。 如果你有太多长寿命的物品,那么Full GC会因为较小的老一代而频繁出现,但如果你的应用程序只是创造了很多短的生物对象,那么这是有效的,所以检查一下。

我的建议是

  • 获取堆转储并分析对象大小,看看是否可以 调整它们
  • 根据您的应用尝试调整新的gen和旧的gen尺寸 分配率
  • 当您使用32位系统时,无法进一步增加堆。因此,最好转向使用64位操作系统的更大系统,以便您可以增加 堆,升级到最新版本的Java7 / 8以利用更好的收集器

答案 1 :(得分:-2)

Java 6现在完全不受支持 - 它的历史可以追溯到2006年,已经有几年的EOL了。建议很简单:升级Java版本并尝试重现问题。

您还使用了冲突的GC选项并将Xms固定到Xmx - 在现代JVM上不建议不要进行容量规划。

升级到Java 7(或理想情况下为8),删除除Xmx以外的所有GC选项,添加GC日志记录(包括PrintGCDetails和PrintTenuringDistribution)并尝试重现该问题。然后查看gc日志,看看它有关终身的说法。