最近发现了频繁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,这表示数组没有达到大对象的标准,直接分配在了新生代