萎缩的幸存者空间导致持续的完整GC

时间:2009-08-13 11:22:34

标签: java garbage-collection jvm

我在使用Tomcat服务器时遇到了这种令人不安的经历:

  • 我们的Hudson服务器;
  • 我们的网络应用程序的暂存版本,每天重新部署5-8次。

问题是我们最终会持续进行垃圾收集,但老一代人却无法填补。我注意到幸存者空间旁边是不存在的,垃圾收集器输出类似于:

[GC 103688K->103688K(3140544K), 0.0226020 secs]
[Full GC 103688K->103677K(3140544K), 1.7742510 secs]
[GC 103677K->103677K(3140544K), 0.0228900 secs]
[Full GC 103677K->103677K(3140544K), 1.7771920 secs]
[GC 103677K->103677K(3143040K), 0.0216210 secs]
[Full GC 103677K->103677K(3143040K), 1.7717220 secs]
[GC 103679K->103677K(3143040K), 0.0219180 secs]
[Full GC 103677K->103677K(3143040K), 1.7685010 secs]
[GC 103677K->103677K(3145408K), 0.0189870 secs]
[Full GC 103677K->103676K(3145408K), 1.7735280 secs]

重启Tomcat之前的堆信息是:

Attaching to process ID 10171, please wait...
Debugger attached successfully.              
Server compiler detected.                    
JVM version is 14.1-b02                      

using thread-local object allocation.
Parallel GC with 8 thread(s)         

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 3221225472 (3072.0MB)
   NewSize          = 2686976 (2.5625MB)   
   MaxNewSize       = 17592186044415 MB    
   OldSize          = 5439488 (5.1875MB)   
   NewRatio         = 2                    
   SurvivorRatio    = 8                    
   PermSize         = 21757952 (20.75MB)   
   MaxPermSize      = 268435456 (256.0MB)  

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 1073479680 (1023.75MB)
   used     = 0 (0.0MB)
   free     = 1073479680 (1023.75MB)
   0.0% used
From Space:
   capacity = 131072 (0.125MB)
   used     = 0 (0.0MB)
   free     = 131072 (0.125MB)
   0.0% used
To Space:
   capacity = 131072 (0.125MB)
   used     = 0 (0.0MB)
   free     = 131072 (0.125MB)
   0.0% used
PS Old Generation
   capacity = 2147483648 (2048.0MB)
   used     = 106164824 (101.24666595458984MB)
   free     = 2041318824 (1946.7533340454102MB)
   4.943684861063957% used
PS Perm Generation
   capacity = 268435456 (256.0MB)
   used     = 268435272 (255.99982452392578MB)
   free     = 184 (1.7547607421875E-4MB)
   99.99993145465851% used

传递给Tomcat的相关JVM标志是:

-verbose:gc -Dsun.rmi.dgc.client.gcInterval=0x7FFFFFFFFFFFFFFE -Xmx3g -XX:MaxPermSize=256m

请注意,幸存者空间在启动时的大小约为40 MB。

我该如何避免这个问题?


更新

JVM版本是

$ java -version
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02, mixed mode)

我将调查PermGen大小,看看是否有帮助 - 可能是幸存者空间的大小不相关。

4 个答案:

答案 0 :(得分:12)

密钥可能为PS Perm Generation,为99.999%(256个MB MB免费中只有184个 字节 )。

通常,我建议你给它更多的烫发,但你已经给它256MB这应该是充足的。我的猜测是你在某些代码生成库中有内存泄漏。 Perm Gen主要用于类的字节码。

答案 1 :(得分:6)

ClassLoader泄漏非常容易 - 只需要通过ClassLoader加载的单个对象由未加载的对象引用。经常重新部署的应用程序将很快填补PermGenSpace。

This article解释了要注意的内容,a followup介绍了如何诊断和解决问题。

答案 2 :(得分:4)

我认为对于连续部署到的应用程序服务器来说,这并不常见。充满你的烫发空间就是课堂所在的地方。请记住,JSP是作为Java类编译的,当您更改JSP时,会生成并加载新类。

我们遇到了这个问题,我们的解决方案是让应用服务器偶尔重启。

这就是我要做的事情:

  1. 将Hudson部署到与登台服务器不同的服务器
  2. 配置Hudson以不时重新启动登台服务器。您可以通过以下两种方式之一执行此操作:
    1. 定期重启(例如,每晚午夜,无论是否有构建活动);或
    2. 让Web应用程序部署作业触发服务器重新启动作业。如果这样做,请确保重新启动作业有一个非常长的静默期(我们将其设置为2小时),这样您就不会为每个构建重新启动服务器(即,如果在2小时内发生两次Web应用程序部署,它们只会触发一台服务器重启。)

答案 3 :(得分:4)

标志-XX:SurvivorRatio设置Eden与幸存者空间之间的比率。根据{{​​3}},默认值为32,其比率为1:32。这与你所看到的一致。这对我来说似乎非常小,虽然我知道只有极少数的物体可以从伊甸园进入幸存者空间。

因此,假设你有很多长寿命的物体,你应该降低幸存者的比例。风险是你在启动阶段只有那些长寿命的对象,因此限制了伊甸园的大小。对于测试服务器,我怀疑这将是一个问题。

我可能还会通过增加-XX:NewRatio(默认值为3)来减小Eden空间的大小。我的直觉说,对于年轻一代来说,一百MB左右就足够了,你只会增加垃圾收集的成本,以便分配如此大量的空间(即,物体将在伊甸园生活太久)。但这只是本能,绝对应该根据您的环境进行验证。


在阅读其他回复之后,还有一个半相关的评论:如果你没有看到因permgen空间耗尽的错误,请不要花时间摆弄它。 permgen与堆的其余部分分开管理。