代码介绍:
jdk提供的工具:
1、在Linux中启动项目:java -cp ref-jvm.jar -XX:+PrintGC -Xms200M -Xmx200M ex13.FullGCProblem
2、top命令,实时显示进程CPU百分比和内存使用情况:可以发现进程7498 占用CPU比较高
等待一段时间:发现CPU使用率在逐渐增加
jinfo:显示JVM参数设置信息
jmap -heap 7498 :可以查看内存使用情况
在不进行任何垃圾回收器指定情况的比例1:1:1
一段时间后 CPU占比很高了
top -p 7498:单独显示7498进程占比CPU
在监控界面输入H,获取当前进程下的所有线程信息
jstack 7498:输出线程信息,nid为16进制
将7500/7501换算成16进制1D4C/1D4D,在界面中查找,问题定位到CPU100%是疯狂的垃圾回收的线程占据的
jstat -gc 7498 2000 10:两秒钟刷新一次GC信息,一共查询10次
各个字段的含义如下:
不够直观,换个方式输出:jstat -gc 7498 5000 20 | awk ‘{print $13,$14,$15,$16,$17}‘
可以发现Full GC在增加,,说明内存不够了
jmap -heap 7498,查看堆内存情况,发现老年代使用率很大了,可能发生了内存泄漏
现在我们定位为是内存问题,CPU100%只是它的体现
jmap -histo 7498 | head -20:显示堆空间对应7498进程对应对象占用大小
问题总结(找到问题)
一般来说,前面那几行,就可以看出,到底是哪些对象占用了内存,这些对象回收不掉,导致了Full GC 里面还有OOM
任务数多于线程数,那么任务会进入阻塞队列,就是一个队列,因为代码中任务数一直多于线程数,所以每0.1s,就会有50个任务进入阻塞对象,50个任务底下有对象,至少对象送进去了,但是没执行,所以导致对象一直都在,同时还回收不了。
为什么回收不了,Executor是一个GCRoots,所以堆中,就会有60多万个对象,阻塞队列中60多万个任务,futureTask,并且这些对象还回收不了。
总结
在JVM出现性能问题的时候(表现上是CPU100%,内存一直占用)
1、出现CPU100%,要从两个角度出发,一个有可能是业务线程疯狂运行,比如说死循环,还有就是GC线程在疯狂的回收,因为在JVM中垃圾回收器主流也是多线程的,所以很容易导致CPU100%;
2、在遇到内存溢出的问题的时候,一般情况下我们要查看系统哪些对象占用比较多,在实际业务代码中,找到对应的对象,分析对应的类,找到为啥这些对象不能回收的原因,就是通过可达性分析算法,JVM的内存区域,还有就是垃圾回收器的基础。
本文参考享学课堂JVM调优实战