Java 缩小幸存者空间会导致持续的完全GC

Java 缩小幸存者空间会导致持续的完全GC,java,garbage-collection,jvm,Java,Garbage Collection,Jvm,我在使用Tomcat服务器时遇到过这种麻烦,它运行: 我们的服务器 我们的web应用程序的暂存版本,每天重新部署5-8次 问题是,我们最终会不断地进行垃圾收集,但老一代人还远远没有被填满。我注意到幸存者空间几乎是不可抗拒的,垃圾收集器的输出类似于: [GC 103688K->103688K(3140544K), 0.0226020 secs] [Full GC 103688K->103677K(3140544K), 1.7742510 secs] [GC 103677K->

我在使用Tomcat服务器时遇到过这种麻烦,它运行:

  • 我们的服务器
  • 我们的web应用程序的暂存版本,每天重新部署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的大小,看看这是否有帮助-可能幸存者空间的大小是无关的。

关键可能是
PS Perm Generation
,它的大小为99.999%(256***MB***空闲空间中只有184字节)


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

我认为这对于持续部署到的应用程序服务器来说并不少见。perm gen空间对您来说已经满了,它是类的归宿。请记住,JSP被编译为Java类,当您更改JSP时,会生成并加载一个新类

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

这就是我要做的:

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

  • 标志
    -XX:SurvivorRatio
    设置Eden和幸存者空间之间的比率。根据,默认值为32,这给出了1:32的比率。这和你看到的是一致的。它对我来说似乎难以置信的小,尽管我知道只有极少数的物体会从伊甸园进入幸存者空间

    所以,假设你有很多长寿命的对象,你应该降低幸存者比率。风险在于,在启动阶段,您只有那些长寿命的对象,因此限制了Eden的大小。对于测试服务器,我怀疑这会成为一个问题

    我可能还会通过增加
    -XX:NewRatio
    (默认值为3)来减小Eden空间的大小。我的直觉是,对于年轻一代来说,100 MB左右就足够了,分配这么大的空间只会增加垃圾收集的成本(也就是说,对象将在伊甸园中生存太久)。但这仅仅是本能,而且肯定应该针对您的环境进行验证



    在阅读了其他回复后,还有一条半相关的评论:如果您没有看到因permgen空间不足而导致的错误,请不要花时间去摆弄它。permgen与堆的其余部分分开管理。

    类加载器很容易泄漏-只需要通过类加载器加载单个对象,而不是由它加载的对象引用。一个不断重新部署的应用程序将很快填满PermGenSpace


    说明应注意的事项,并说明如何诊断和解决问题。

    没错,它确实最大限度地利用了
    PermGen
    空间。我以前没有注意到这一点,因为我希望它像往常一样抛出一个
    OutOfMemoryError
    。我要试一试。至于代码生成泄漏,我(不幸地)在任何非平凡的web应用程序中都看到了这个PermGen问题。我们只是在重新部署一个基于Spring的应用程序。在多次重新部署之后,PermGen的使用将耗尽是一个常见的问题;但你仍然可以找出谁泄露了这些课程。只需像平常一样使用探查器,但检查未清理的对象(资源、数据库连接等)。接下来发生这种情况时,我将进行堆转储,看看会发生什么。14.1是HS构建,而不是java版本。我将用细节更新问题。好的,我将删除帖子的该部分;我也有同样的问题,使用同样的解决方案,我的webapp的登台版本将由Hudson在每次构建中部署。解决方案只要每小时重新启动这个Tomcat,这对我们来说是可以的,因为它只用于测试。