大对象引起的频繁FULL GC


最近发现了频繁FULL GC的情况,查看GC日志后,发现每次FULL GC后,老年代都能回收大半以上的空间,这意味着有很多临时对象被分配到了老年代。

jmap命令导出堆转储文件,然后用jvisualvm导入后进行分析,发现char[]占据了最多了内存。

其中有大量的对象达到了3M,被直接担保分配进了老年代,因为暂时不知道这些对象是怎么产生的,最快的解决办法就是增大担保分配的阈值。

下面就是测试过程

/**
 -server
 -XX:+UseConcMarkSweepGC
 -Xms20M
 -Xmx20M
 -Xmn10M
 -XX:SurvivorRatio=8
 -XX:PretenureSizeThreshold=2000000
 -XX:+PrintGC
 -XX:+PrintGCDetails
 -XX:+PrintGCDateStamps
 -XX:+PrintHeapAtGC
 -Xloggc:/var/logs/PretenureSizeThreshold.log
 -XX:+HeapDumpOnOutOfMemoryError
 -XX:HeapDumpPath=/var/dumps/PretenureSizeThreshold.hprof
 */
public class PretenureSizeThreshold {

    private static final int _1MB = 1000 * 1000;

    public static void main(String[] args) throws Exception{
        RuntimeMXBean mxBean =  ManagementFactory.getRuntimeMXBean();
        System.out.println(mxBean.getName());
        String pid = mxBean.getName().split("@")[0];

        byte[] allocation = new byte[3*_1MB];

        while (true){
            Thread.sleep(1000);
        }

    }
}
D:\Doc\MyRepo\learning-java>jmap -heap 14000
Attaching to process ID 14000, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 20971520 (20.0MB)
   NewSize                  = 10485760 (10.0MB)
   MaxNewSize               = 10485760 (10.0MB)
   OldSize                  = 10485760 (10.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 9437184 (9.0MB)
   used     = 2748888 (2.6215438842773438MB)
   free     = 6688296 (6.378456115722656MB)
   29.128265380859375% used
Eden Space:
   capacity = 8388608 (8.0MB)
   used     = 2748888 (2.6215438842773438MB)
   free     = 5639720 (5.378456115722656MB)
   32.7692985534668% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 10485760 (10.0MB)
   used     = 3000016 (2.8610382080078125MB)
   free     = 7485744 (7.1389617919921875MB)
   28.610382080078125% used

1815 interned Strings occupying 162040 bytes.

老年代占用的空间为3000016,这表示数组通过担保分配进入了老年代,多出来的16是对象头的体积

修改启动参数-XX:PretenureSizeThreshold=4000000

D:\Doc\MyRepo\learning-java>jmap -heap 2356
Attaching to process ID 2356, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 20971520 (20.0MB)
   NewSize                  = 10485760 (10.0MB)
   MaxNewSize               = 10485760 (10.0MB)
   OldSize                  = 10485760 (10.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 9437184 (9.0MB)
   used     = 5748624 (5.4823150634765625MB)
   free     = 3688560 (3.5176849365234375MB)
   60.91461181640625% used
Eden Space:
   capacity = 8388608 (8.0MB)
   used     = 5748624 (5.4823150634765625MB)
   free     = 2639984 (2.5176849365234375MB)
   68.52893829345703% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 10485760 (10.0MB)
   used     = 0 (0.0MB)
   free     = 10485760 (10.0MB)
   0.0% used

1815 interned Strings occupying 162040 bytes.

此时,老年代占用0,这表示数组没有达到大对象的标准,直接分配在了新生代