表现:频繁FULLGC,且该服务超时。
1.top查看后该java进程的运行状况为
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15178 x 20 0 7314m 4.2g 10m S 98.9 55.1 4984:05 java
看到:RES 占用4.2g CPU占用98%
2.top -H -p 15178 查看线程情况
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15234 x 20 0 7314m 4.2g 10m R 70.2 55.1 781:50.32 java
15250 x 20 0 7314m 4.2g 10m S 52.9 55.1 455:12.27 java
一个PID为 15234 的轻量级进程,对应于java中的线程的本地线程号,占用CPU和内存最高。
3. 通过printf '%x\n' 15234计算出16进制的 3b82
通过jstack -l 15178 然后搜索该线程,发现其为
"Concurrent Mark-Sweep GC Thread" os_prio=0 tid=0x00007ff3e4064000 nid=0x3b82 runnable
定位了确实由GC导致的系统不可用。
4.jinfo -flags 查看该VM参数
jmap -heap 查看统计结果
使用jstat -gcutil 15178 1s观察一段时间GC状况
jstat -gccause 15178 1s
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
100.00 0.00 100.00 100.00 97.78 95.59 1906 26.575 61433 217668.188 217694.763 Allocation Failure Allocation Failure
0.00 0.00 96.51 100.00 97.78 95.59 1906 26.575 61433 217672.991 217699.566 Allocation Failure No GC
100.00 0.00 100.00 100.00 97.78 95.59 1906 26.575 61434 217672.991 217699.566 Allocation Failure Allocation Failure
100.00 0.00 100.00 100.00 97.78 95.59 1906 26.575 61434 217672.991 217699.566 Allocation Failure Allocation Failure
100.00 0.00 100.00 100.00 97.78 95.59 1906 26.575 61434 217672.991 217699.566 Allocation Failure Allocation Failure
可以看到Old区满了,并且Eden区域的对象没有触发YGC直接晋升到Old区中,但是Full GC没有释放出空间。这是由于在当老年代的连续空间小于新生代所有对象大小时,MinorGC前会检查下平均每次晋升到Old区的大小是否大于Old区的剩余空间,如果大于或者当前的设置HandlePromotionFailure为false则直接触发FullGc,否则会先进行MinorGC。
关于FullGC和MajorGC的区别,可以不要太纠结.
5.jmap -histo 15178 | less 查看一下对象实例数量和空间占用
看到前面的一种数据各占用几百兆内存。总和在1935483656,和堆空间基本相同。
主要寻找这个列表中的业务对象和集合对象
num #instances #bytes class name
----------------------------------------------
1: 14766305 796031864 [C
2: 14763842 354332208 java.lang.String
3: 8882440 213178560 java.lang.Long
4: 1984104 174601152 com.x.x.x.model.Order
其中的Order引起我们的注意。
后续见原文...
https://mp.weixin.qq.com/s/U9KLh9PqvL6EpyIBm9uCTw