JVM 因无限 GC 而挂起

5

我有一个在Glassfish服务器上运行的庞大应用程序,它创建了很多短暂的对象,我在JVM中设置了以下GC配置。

-XX:+DisableExplicitGC
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:-UseAdaptiveSizePolicy
-XX:PermSize=256m
-XX:MaxPermSize=1024m
-Xms7g
-Xmx7g
-XX:NewRatio=2

但是JVM出现了无限GC,我不得不重启JVM。从GC日志中我得到了以下信息。

2.855: [GC 734029K->9736K(7034240K), 0.0133500 secs]
2.869: [Full GC 9736K->9501K(7034240K), 0.1043570 secs]
13.254: [GC 681231K->26506K(7034240K), 0.0251050 secs]
13.280: [Full GC 26506K->26082K(7034240K), 0.2904930 secs]
13.589: [GC 103156K->26224K(7034240K), 0.0015940 secs]
13.590: [Full GC 26224K->24440K(7034240K), 0.2254710 secs]
35.478: [GC 1859512K->131673K(7034240K), 0.0781300 secs]
41.603: [GC 1966745K->351954K(7034240K), 0.1858590 secs]
46.012: [GC 2187026K->502362K(7034240K), 0.2329020 secs]
51.850: [GC 2337434K->608654K(7034240K), 0.2012410 secs]
72.584: [GC 2443726K->727923K(7034240K), 0.2203390 secs]
80.239: [GC 2562995K->894770K(7034240K), 0.2323490 secs]
106.221: [GC 2729842K->1265916K(7034240K), 0.2800630 secs]

请告诉我,这个用例的jvm GC设置是否正确。或者,任何帮助解决这些问题的帮助都将不胜感激。
更新 我还获得了jmap堆转储信息。即使没有人使用,PS老一代似乎仍持有大部分内存。它并没有增加(在内存泄漏的情况下会增加)。
using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 7516192768 (7168.0MB)
   NewSize          = 5439488 (5.1875MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 268435456 (256.0MB)
   MaxPermSize      = 1073741824 (1024.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 2244935680 (2140.9375MB)
   used     = 863166976 (823.18017578125MB)
   free     = 1381768704 (1317.75732421875MB)
   38.44951923076923% used
From Space:
   capacity = 112525312 (107.3125MB)
   used     = 47609824 (45.404266357421875MB)
   free     = 64915488 (61.908233642578125MB)
   42.31032392071928% used
To Space:
   capacity = 114753536 (109.4375MB)
   used     = 0 (0.0MB)
   free     = 114753536 (109.4375MB)
   0.0% used
PS Old Generation
   capacity = 5010817024 (4778.6875MB)
   used     = 4385643424 (4182.475494384766MB)
   free     = 625173600 (596.2120056152344MB)
   87.52351967741699% used
PS Perm Generation
   capacity = 458031104 (436.8125MB)
   used     = 432700088 (412.6549606323242MB)
   free     = 25331016 (24.15753936767578MB)
   94.46958606549131% used

3
为什么你在使用ParallelOldGC?它不比普通的并行垃圾回收器更差吗? - Mister Smith
4
我没有看到无限GC的任何证据。你能给我们提供一下在你不得不终止它之前发生了什么的日志吗? - Peter Lawrey
2
我同意@Peter Lawrey的看法。在你的应用程序中,这看起来像是一个无限循环。如果我读对了,GC日志显示JVM每15秒只花费不到0.3秒的时间运行垃圾收集器。 - Stephen C
1
我曾经看到过无限GC,当使用后的GC与之前的GC一样高或更高,并且反复这样做时。需要注意的是,如果后续大小相同或更大,并且GC之间似乎没有时间,则需要检查。 - Peter Lawrey
@Peter Lawrey 我们也怀疑是同样的问题。Full GC 无法清除任何东西,导致另一个 Full GC 导致冻结。完整GC前后的大小保持不变。并且所有对象都在 PS Old Generation 中。为什么它没有清除 PS Old Generation 中的对象呢? - Dinesh Varadharajan
1
我只在创建大量对象并填充旧一代空间时看到过这种情况。我相信正确的行为应该是产生OutOfMemoryError,但出于某种原因它没有发生。然而,您还没有向我们展示证明此行为的日志,因此我不能确定是否是同一件事。 - Peter Lawrey
3个回答

4

你能取消ParallelOldGC吗?这似乎会导致内存碎片。

或者你可以尝试添加

-XX:+UseCMSCompactAtFullCollection和-XX:CMSFullGCsBeforeCompaction=0

另外,你也可以添加-server参数,因为它似乎总是用于服务器端的Java应用程序。

不确定它是否有帮助,因为我无法代替你试验。


2

不确定这是否有帮助,但您可以使用额外的参数:

      -XX:ParallelGCThreads=10  //10 threads for GC

减少默认的GC线程数。

2
在你的系统中,线程的数量应该等于CPU核心的数量吗? - AngerClown
1
@AngerClown 这些是专门用于GC的线程。通常情况下,您会将此数量设置为低于默认值,因为默认值可能过高,从而释放实际计算所需的线程。因此,您不应使用可用的所有线程,而只使用其中的一部分。 - Mister Smith

0

问题可能是Xmx和Xms都设置为相同的大值7g。为什么不将Xms设置为较低的值?在我看来,这应该得到纠正。


我们已经尝试过了。我们将Xms设置为1G,但我们无法解决这个问题。谢谢您的建议。 - Dinesh Varadharajan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接