JVM调优
Jmap
Jmap -histo pid
当服务器内存占用飙高,可以使用Jmap查看Java应用内存信息,实例个数以及占用内存大小。
/**
* 测试代码
*/
public class HeapTest {
private static List<Company> list = new ArrayList<>();
public static void main(String[] args) {
while (true){
list.add(new Company());
}
}
}
class Company{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
[root@master ~]# jmap -histo 260613
num #instances #bytes class name
----------------------------------------------
1: 70091071 1121457136 com.jvm.Company
2: 513 280390104 [Ljava.lang.Object;
3: 882 84064 [C
4: 471 54216 java.lang.Class
5: 9 25040 [B
6: 869 20856 java.lang.String
7: 256 4096 java.lang.Integer
8: 91 3640 java.lang.ref.SoftReference
9: 109 3488 java.util.Hashtable$Entry
10: 89 3000 [I
11: 7 2632 java.lang.Thread
12: 58 2024 [Ljava.lang.String;
13: 38 1824 sun.util.locale.LocaleObjectCache$CacheEntry
14: 51 1632 java.util.concurrent.ConcurrentHashMap$Node
15: 19 1216 java.net.URL
16: 2 1064 [Ljava.lang.invoke.MethodHandle;
17: 1 1040 [Ljava.lang.Integer;
18: 26 1040 java.io.ObjectStreamField
jmap -histo:live pid #查看当前存活的实例
当发生内存溢出时,可以根据GC日志找到问题代码。
[root@master ext]# java -XX:+PrintGCDetails com.jvm.HeapTest
[GC (Allocation Failure) [PSYoungGen: 31232K->5116K(36352K)] 31232K->21036K(119808K), 0.0260969 secs] [Times: user=0.07 sys=0.01, real=0.03 secs]
[GC (Allocation Failure) [PSYoungGen: 36348K->5104K(67584K)] 52268K->40435K(151040K), 0.0301175 secs] [Times: user=0.08 sys=0.01, real=0.03 secs]
[GC (Allocation Failure) [PSYoungGen: 55880K->5104K(67584K)] 91211K->107276K(170496K), 0.1080058 secs] [Times: user=0.15 sys=0.08, real=0.11 secs]
[Full GC (Ergonomics) [PSYoungGen: 5104K->0K(67584K)] [ParOldGen: 102172K->80415K(205312K)] 107276K->80415K(272896K), [Metaspace: 2959K->2959K(1056768K)], 0.9571864 secs] [Times: user=2.76 sys=0.07, real=0.96 secs]
[GC (Allocation Failure) [PSYoungGen: 62464K->5120K(100864K)] 178934K->154966K(306176K), 0.1663656 secs] [Times: user=0.58 sys=0.02, real=0.17 secs]
[Full GC (Ergonomics) [PSYoungGen: 5120K->0K(100864K)] [ParOldGen: 149846K->138855K(305664K)] 154966K->138855K(406528K), [Metaspace: 2959K->2959K(1056768K)], 1.2778122 secs] [Times: user=4.28 sys=0.01, real=1.27 secs]
[GC (Allocation Failure) [PSYoungGen: 95744K->5120K(130048K)] 288682K->288874K(435712K), 0.2113250 secs] [Times: user=0.77 sys=0.05, real=0.22 secs]
[Full GC (Ergonomics) [PSYoungGen: 5120K->0K(130048K)] [ParOldGen: 283754K->252595K(510464K)] 288874K->252595K(640512K), [Metaspace: 2959K->2959K(1056768K)], 2.3398999 secs] [Times: user=6.97 sys=0.01, real=2.34 secs]
[GC (Allocation Failure) [PSYoungGen: 124928K->98787K(201728K)] 377523K->377591K(712192K), 0.1152322 secs] [Times: user=0.40 sys=0.03, real=0.11 secs]
[GC (Allocation Failure) [PSYoungGen: 201699K->120672K(236032K)] 602189K->521161K(746496K), 0.2797464 secs] [Times: user=1.02 sys=0.03, real=0.28 secs]
[GC (Allocation Failure) [PSYoungGen: 223584K->152576K(245760K)] 624073K->624217K(756224K), 0.5179186 secs] [Times: user=1.98 sys=0.07, real=0.52 secs]
[Full GC (Ergonomics) [PSYoungGen: 152576K->59363K(245760K)] [ParOldGen: 471641K->510462K(857088K)] 624217K->569825K(1102848K), [Metaspace: 2959K->2959K(1056768K)], 5.3441450 secs] [Times: user=16.13 sys=0.01, real=5.34 secs]
[GC (Allocation Failure) [PSYoungGen: 152547K->152704K(303104K)] 845537K->845694K(1160192K), 0.3155097 secs] [Times: user=1.15 sys=0.04, real=0.31 secs]
[GC (Allocation Failure) [PSYoungGen: 245888K->221696K(340480K)] 938878K->938918K(1197568K), 0.4408531 secs] [Times: user=1.67 sys=0.08, real=0.44 secs]
[GC (Allocation Failure) [PSYoungGen: 340480K->221696K(340480K)] 1331496K->1331696K(1471488K), 0.6061501 secs] [Times: user=2.19 sys=0.13, real=0.61 secs]
[Full GC (Ergonomics) [PSYoungGen: 221696K->0K(340480K)] [ParOldGen: 1110000K->1027081K(1332736K)] 1331696K->1027081K(1673216K), [Metaspace: 2959K->2959K(1056768K)], 8.5374366 secs] [Times: user=25.74 sys=0.01, real=8.53 secs]
[GC (Allocation Failure) [PSYoungGen: 118784K->118880K(364544K)] 1145865K->1145961K(1697280K), 0.2941721 secs] [Times: user=1.16 sys=0.01, real=0.30 secs]
[GC (Allocation Failure) [PSYoungGen: 272992K->154240K(375808K)] 1300073K->1300345K(1708544K), 0.6918694 secs] [Times: user=2.65 sys=0.04, real=0.69 secs]
[GC (Allocation Failure) [PSYoungGen: 225119K->69344K(432128K)] 1371224K->1369881K(1764864K), 0.6465283 secs] [Times: user=2.43 sys=0.14, real=0.65 secs]
[Full GC (Ergonomics) [PSYoungGen: 69344K->36499K(432128K)] [ParOldGen: 1300537K->1332728K(1332736K)] 1369881K->1369227K(1764864K), [Metaspace: 2959K->2959K(1056768K)], 11.4042660 secs] [Times: user=43.38 sys=0.01, real=11.40 secs]
[Full GC (Allocation Failure) [PSYoungGen: 36499K->36499K(432128K)] [ParOldGen: 1332728K->1332716K(1332736K)] 1369227K->1369216K(1764864K), [Metaspace: 2959K->2959K(1056768K)], 9.7899248 secs] [Times: user=37.66 sys=0.00, real=9.79 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:267)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:241)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:233)
at java.util.ArrayList.add(ArrayList.java:464)
at com.jvm.HeapTest.main(HeapTest.java:17)
Heap
PSYoungGen total 432128K, used 44916K [0x00000000d7580000, 0x00000000ffc00000, 0x0000000100000000)
eden space 210432K, 3% used [0x00000000d7580000,0x00000000d7db83a8,0x00000000e4300000)
from space 221696K, 16% used [0x00000000f1b80000,0x00000000f3f24f90,0x00000000ff400000)
to space 221696K, 0% used [0x00000000e4300000,0x00000000e4300000,0x00000000f1b80000)
ParOldGen total 1332736K, used 1332716K [0x0000000086000000, 0x00000000d7580000, 0x00000000d7580000)
object space 1332736K, 99% used [0x0000000086000000,0x00000000d757b248,0x00000000d7580000)
Metaspace used 2996K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 282K, capacity 386K, committed 512K, reserved 1048576K
- num:序号
- instances:实例数量
- bytes:占用空间大小
- class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
Jmap -heap pid
jmap -heap pid #查看堆内存信息
C:\Users\jay>jmap -heap 12748
Attaching to process ID 12748, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.261-b12
using thread-local object allocation.
Parallel GC with 13 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 8573157376 (8176.0MB)
NewSize = 178782208 (170.5MB)
MaxNewSize = 2857369600 (2725.0MB)
OldSize = 358088704 (341.5MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 220200960 (210.0MB)
used = 5190456 (4.950004577636719MB)
free = 215010504 (205.04999542236328MB)
2.357145036969866% used
From Space:
capacity = 13107200 (12.5MB)
used = 0 (0.0MB)
free = 13107200 (12.5MB)
0.0% used
To Space:
capacity = 22020096 (21.0MB)
used = 0 (0.0MB)
free = 22020096 (21.0MB)
0.0% used
PS Old Generation
capacity = 222298112 (212.0MB)
used = 16611120 (15.841598510742188MB)
free = 205686992 (196.1584014892578MB)
7.472452127708579% used
15765 interned Strings occupying 2109464 bytes.
jmap -dump:format=b,file=heap.hprof pid #导出堆内存信息
#设置内存溢出时自动导出dump文件:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ #指定路径
-XX:+PrintGCDetails 打印GC日志
Jstack
使用Jstack可以查找Java应用中是否存在死锁。
jstack pid
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x000002173b5f95d8 (object 0x0000000715d09a30, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000002173b5f6d48 (object 0x0000000715d09a40, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.jvm.DeadLockTest.lambda$main$1(DeadLockTest.java:35)
- waiting to lock <0x0000000715d09a30> (a java.lang.Object)
- locked <0x0000000715d09a40> (a java.lang.Object)
at com.jvm.DeadLockTest$$Lambda$2/1225358173.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.jvm.DeadLockTest.lambda$main$0(DeadLockTest.java:22)
- waiting to lock <0x0000000715d09a40> (a java.lang.Object)
- locked <0x0000000715d09a30> (a java.lang.Object)
at com.jvm.DeadLockTest$$Lambda$1/1587487668.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
预防死锁的发生
- 使用多个锁,设计锁的获取顺序,图形化表示出来;
- 使用可以设定超时时间的锁,比如ReentrantLock.tryLock(long timeout, TimeUnit unit)方法
使用Jstack找出占用CPU最高的线程堆栈信息
-
使用top -p 257949,显示Java进程的内存、CPU使用情况;
[root@master ~]# top -p 257949 top - 00:09:27 up 47 days, 15:42, 4 users, load average: 0.87, 0.34, 0.16 Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie %Cpu(s): 25.7 us, 0.6 sy, 0.0 ni, 73.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 7990068 total, 3953816 free, 1776852 used, 2259400 buff/cache KiB Swap: 0 total, 0 free, 0 used. 5799316 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 257949 root 20 0 4486708 22100 11060 S 100.0 0.3 1:56.99 java
-
按H,获取每个线程的内存情况;
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 257950 root 20 0 4486708 22100 11060 R 99.9 0.3 3:37.19 java 257949 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 java 257951 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 java 257952 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 java 257953 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 java 257954 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 java 257955 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 VM Thread 257956 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 Reference Handl 257957 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 Finalizer 257958 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 Signal Dispatch 257959 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 C2 CompilerThre 257960 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.01 C2 CompilerThre 257961 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 C1 CompilerThre 257962 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.00 Service Thread 257963 root 20 0 4486708 22100 11060 S 0.0 0.3 0:00.12 VM Periodic Tas
-
找到内存和CPU占用最高的线程tid 257950;
-
转为十六进制得到nid 3ef9e,此线程id的十六进制表示;
-
jstack pid | grep -A 20 nid 从堆栈中找到导致CPU飙高的调用方法;
[root@master ~]# jstack 257949 | grep -A 20 3ef9e "main" #1 prio=5 os_prio=0 tid=0x00007fe9f404b800 nid=0x3ef9e runnable [0x00007fe9fe46c000] java.lang.Thread.State: RUNNABLE at com.jvm.JVMTest.main(JVMTest.java:38) "VM Thread" os_prio=0 tid=0x00007fe9f40d6000 nid=0x3efa3 runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fe9f405e000 nid=0x3ef9f runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fe9f4060000 nid=0x3efa0 runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007fe9f4062000 nid=0x3efa1 runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007fe9f4063800 nid=0x3efa2 runnable "VM Periodic Task Thread" os_prio=0 tid=0x00007fe9f4131000 nid=0x3efab waiting on condition JNI global references: 5
-
查看对应的堆栈信息找出可能存在问题的代码;
找到com.jvm.JVMTest.main(JVMTest.java:38)
Jinfo
Jinfo可以查看正在运行的Java应用程序的参数,比如查看Java系统参数:
jinfo -sysprops pid
Jstat
Jstat可以查看堆内存各部分的使用量,以及加载类的数量。
#命令格式:
jstat [-命令选项]<vmid>[间隔时间毫秒][查询次数]
垃圾回收统计
jstat -gc pid,评估应用内存使用及GC压力整体情况
C:\Users\jay>jstat -gc 12748 1000 5
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
12800.0 21504.0 0.0 0.0 215040.0 7864.4 217088.0 16221.8 33024.0 31213.3 4608.0 4252.1 4 0.031 2 0.075 0.106
12800.0 21504.0 0.0 0.0 215040.0 7864.4 217088.0 16221.8 33024.0 31213.3 4608.0 4252.1 4 0.031 2 0.075 0.106
12800.0 21504.0 0.0 0.0 215040.0 7864.4 217088.0 16221.8 33024.0 31213.3 4608.0 4252.1 4 0.031 2 0.075 0.106
12800.0 21504.0 0.0 0.0 215040.0 7864.4 217088.0 16221.8 33024.0 31213.3 4608.0 4252.1 4 0.031 2 0.075 0.106
12800.0 21504.0 0.0 0.0 215040.0 7864.4 217088.0 16221.8 33024.0 31213.3 4608.0 4252.1 4 0.031 2 0.075 0.106
- S0C:第一个幸存区的大小,单位KB
- S1C:第二个幸存区的大小
- S0U:第一个幸存区的使用大小
- S1U:第二个幸存区的使用大小
- EC:伊甸园区的大小
- EU:伊甸园区的使用大小
- OC:老年代大小
- OU:老年代使用大小
- MC:方法区大小(元空间)
- MU:方法区使用大小
- CCSC:压缩类空间大小
- CCSU:压缩类空间使用大小
- YGC:年轻代垃圾回收次数
- YGCT:年轻代垃圾回收消耗时间,单位s
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间,单位s
- GCT:垃圾回收消耗总时间,单位s
堆内存统计
jstat -gccapacity pid
C:\Users\jay>jstat -gccapacity 12748
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
174592.0 2790400.0 258048.0 12800.0 21504.0 215040.0 349696.0 5581824.0 217088.0 217088.0 0.0 1077248.0 33024.0 0.0 1048576.0 4608.0 4 2
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0C:第一个幸存区大小
- S1C:第二个幸存区的大小
- EC:伊甸园区的大小
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- OC:当前老年代大小
- MCMN:最小元数据容量
- MCMX:最大元数据容量
- MC:当前元数据空间大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代gc次数
- FGC:老年代GC次数
新生代垃圾回收统计
jstat -gcnew pid
C:\Users\jay>jstat -gcnew 12748 1000 3
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
12800.0 21504.0 0.0 0.0 7 15 21504.0 215040.0 7864.4 4 0.031
12800.0 21504.0 0.0 0.0 7 15 21504.0 215040.0 7864.4 4 0.031
12800.0 21504.0 0.0 0.0 7 15 21504.0 215040.0 7864.4 4 0.031
- S0C:第一个幸存区的大小
- S1C:第二个幸存区的大小
- S0U:第一个幸存区的使用大小
- S1U:第二个幸存区的使用大小
- TT:对象在新生代存活的次数
- MTT:对象在新生代存活的最大次数
- DSS:期望的幸存区大小
- EC:伊甸园区的大小
- EU:伊甸园区的使用大小
- YGC:年轻代垃圾回收次数
- YGCT:年轻代垃圾回收消耗时间
新生代内存统计
jstat -gcnewcapacity pid
C:\Users\jay>jstat -gcnewcapacity 12748 1000 3
NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
174592.0 2790400.0 258048.0 929792.0 12800.0 929792.0 21504.0 2789376.0 215040.0 4 2
174592.0 2790400.0 258048.0 929792.0 12800.0 929792.0 21504.0 2789376.0 215040.0 4 2
174592.0 2790400.0 258048.0 929792.0 12800.0 929792.0 21504.0 2789376.0 215040.0 4 2
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0CMX:最大幸存1区大小
- S0C:当前幸存1区大小
- S1CMX:最大幸存2区大小
- S1C:当前幸存2区大小
- ECMX:最大伊甸园区大小
- EC:当前伊甸园区大小
- YGC:年轻代垃圾回收次数
- FGC:老年代回收次数
老年代垃圾回收统计
jstat -gcold pid
C:\Users\jay>jstat -gcold 12748 1000 3
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
33024.0 31213.3 4608.0 4252.1 217088.0 16221.8 4 2 0.075 0.106
33024.0 31213.3 4608.0 4252.1 217088.0 16221.8 4 2 0.075 0.106
33024.0 31213.3 4608.0 4252.1 217088.0 16221.8 4 2 0.075 0.106
- MC:方法区大小
- MU:方法区使用大小
- CCSC:压缩类空间大小
- CCSU:压缩类空间使用大小
- OC:老年代大小
- OU:老年代使用大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
老年代内存统计
jstat -gcoldcapacity pid
C:\Users\jay>jstat -gcoldcapacity 12748 1000 3
OGCMN OGCMX OGC OC YGC FGC FGCT GCT
349696.0 5581824.0 217088.0 217088.0 4 2 0.075 0.106
349696.0 5581824.0 217088.0 217088.0 4 2 0.075 0.106
349696.0 5581824.0 217088.0 217088.0 4 2 0.075 0.106
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- OC:老年代大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
元数据空间内存统计
jstat -gcmetacapacity pid
C:\Users\jay>jstat -gcmetacapacity 12748 1000 3
MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT
0.0 1077248.0 33024.0 0.0 1048576.0 4608.0 4 2 0.075 0.106
0.0 1077248.0 33024.0 0.0 1048576.0 4608.0 4 2 0.075 0.106
0.0 1077248.0 33024.0 0.0 1048576.0 4608.0 4 2 0.075 0.106
- MCMN:最小元数据容量
- MCMX:最大元数据容量
- MC:当前元数据空间大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
Jstat -gcutil pid
C:\Users\jay>jstat -gcutil 12748 1000 3
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 3.66 7.47 94.52 92.28 4 0.031 2 0.075 0.106
0.00 0.00 3.66 7.47 94.52 92.28 4 0.031 2 0.075 0.106
0.00 0.00 3.66 7.47 94.52 92.28 4 0.031 2 0.075 0.106
- S0:幸存1区当前使用比例
- S1:幸存2区当前使用比例
- E:伊甸园区使用比例
- O:老年代使用比例
- M:元数据区使用比例
- CCS:压缩使用比例
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
JVM运行情况评估
用 jstat gc -pid 命令可以计算出如下一些关键数据,有了这些数据就可以采用之前介绍过的优化思路,先给自己的系统设置一些初始性的JVM参数,比如堆内存大小,年轻代大小,Eden和Survivor的比例,老年代的大小,大对象的阈值,大龄对象进入老年代的阈值等。
年轻代对象增长的速率
可以执行命令 jstat -gc pid 1000 10 (每隔1秒执行1次命令,共执行10次),通过观察EU(eden区的使用)来估算每秒eden大概新增多少对象,如果系统负载不高,可以把频率1秒换成1分钟,甚至10分钟来观察整体情况。注意,一般系统可能有高峰期和日常期,所以需要在不同的时间分别估算不同情况下对象增长速率。
Young GC的触发频率和每次耗时
知道年轻代对象增长速率我们就能推根据eden区的大小推算出Young GC大概多久触发一次,Young GC的平均耗时可以通过 YGCT/YGC 公式算出,根据结果我们大概就能知道系统大概多久会因为Young GC的执行而卡顿多久。
每次Young GC后有多少对象存活和进入老年代
这个因为之前已经大概知道Young GC的频率,假设是每5分钟一次,那么可以执行命令 jstat -gc pid 300000 10 ,观察每次结果eden,survivor和老年代使用的变化情况,在每次gc后eden区使用一般会大幅减少,survivor和老年代都有可能增长,这些增长的对象就是每次Young GC后存活的对象,同时还可以看出每次Young GC后进去老年代大概多少对象,从而可以推算出老年代对象增长速率。
Full GC的触发频率和每次耗时
知道了老年代对象的增长速率就可以推算出Full GC的触发频率了,Full GC的每次耗时可以用公式 FGCT/FGC 计算得出。
优化思路
优化思路其实简单来说就是尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里。尽量别让对象进入老年代。尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。