--- title: 大对象引起的频繁FULL GC tags: java jvm categories: java --- 最近发现了频繁FULL GC的情况,查看GC日志后,发现每次FULL GC后,老年代都能回收大半以上的空间,这意味着有很多临时对象被分配到了老年代。 用`jmap`命令导出堆转储文件,然后用jvisualvm导入后进行分析,发现char[]占据了最多了内存。 其中有大量的对象达到了3M,被直接担保分配进了老年代,因为暂时不知道这些对象是怎么产生的,最快的解决办法就是增大担保分配的阈值。 下面就是测试过程 ~~~java /** -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); } } } ~~~ ~~~text 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` ~~~text 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,这表示数组没有达到大对象的标准,直接分配在了新生代