排查CPU使用率过高
1.先通过top
命令找到消耗CPU很高的进程ID,假设是我们找到的进程ID是10923
2.执行top -p 10923 -H
,获取当前进程下所有线程的信息
3.找到其中消耗CPU特别高的线程ID,如10924
4.将第三步获取到的线程ID转成十六进制10924 -> 0x2aac
5.执行jstack 10923 > jstack10923.out
对当前进程做dump操作,并输出所有的线程信息
6.找到对应的线程信息内容cat jstack10923.out | grep 2aac -C 10
排查OOM的问题
1.先通过top
命令找到消耗内存很高的进程ID,假设是我们找到的进程ID是10923
2.使用jstat -gcutil 10923 1000 10
工具按照指定间隔,看一下统计信息,这里会每隔一段时间显示一下,包括新生代的两个S0、s1区、Eden区,以及老年代的内存使用率,还有young gc以及full gc的次数。其中1000代表的是1000毫秒,10代表的打印10次
1 | [root@zyj tmp]# jstat -gcutil 10923 1000 10 |
1 | S0 Heap上的Survivor space 0区已使用空间的百分比 |
1 | S0 S1 E O YGC FGC |
其实如果大家了解原理,应该知道,一般来说大量的对象涌入内存,结果始终不能回收,会出现的情况就是,快速撑满年轻代,然后young gc几次,根本回收不了什么对象,导致survivor区根本放不下,然后大量对象涌入老年代。老年代很快也满了,然后就频繁full gc,但是也回收不掉。
然后对象持续增加不就oom了,内存放不下了,爆了呗。
所以jstat先看一下基本情况,马上就能看出来,其实就是大量对象没法回收,一直在内存里占据着,然后就差不多内存快爆了。
3.使用jmap -histo 10923
命令查看可以打印出当前堆中所有每个类的实例数量和内存占用,如下,class name是每个类的类名[B是byte类型,[C是char类型,[I是int类型
,bytes是这个类的所有示例占用内存大小,instances是这个类的实例数量。
4.使用jmap -dump:format=b,file=/tmp/10923dump.hprof 10923
接着就可以使用Jprofiler工具看下是哪个对象占用空间最大了。
人家肯定会问你有没有处理过线上的问题,你就说有,最简单的,你说有个小伙子用了本地缓存,就放map里,结果没控制map大小,可以无限扩容,最终导致内存爆了,后来解决方案就是用了一个GuavaCache
框架,通过过期策略清理掉旧数据,控制内存占用就好了。
另外,务必提到,线上jvm必须配置-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=/path/heap/dump。因为这样就是说OOM的时候自动导出一份内存快照,你就可以分析发生OOM时的内存快照了,到底是哪里出现的问题。