1.线上日志分析的步骤
- 通过 top命令查看CPU情况,如果CPU比较高,则通过top -Hp 命令查看当前进程的各个线程运行情况,找出CPU过高的线程之后,将其线程id转换为十六进制的表现形式,然后在jstack日志中查看该线程主要在进行的工作。这里又分为两种情况
- 如果是正常的用户线程,则通过该线程的堆栈信息查看其具体是在哪处用户代码处运行比较消耗CPU;
- 如果该线程是VM Thread,则通过jstat -gcutil 命令监控当前系统的GC状况,然后通过jmap dump:format=b,file= 导出系统当前的内存数据。导出之后将内存情况放到eclipse的mat工具中进行分析即可得出内存中主要是什么对象比较消耗内存,进而可以处理相关代码;
- 如果通过 top 命令看到CPU并不高,并且系统内存占用率也比较低。此时就可以考虑是否是由于另外三种情况导致的问题。具体的可以根据具体情况分析:
- 如果是接口调用比较耗时,并且是不定时出现,则可以通过压测的方式加大阻塞点出现的频率,从而通过jstack查看堆栈信息,找到阻塞点;
- 如果是某个功能突然出现停滞的状况,这种情况也无法复现,此时可以通过多次导出jstack日志的方式对比哪些用户线程是一直都处于等待状态,这些线程就是可能存在问题的线程;
- 如果通过jstack可以查看到死锁状态,则可以检查产生死锁的两个线程的具体阻塞点,从而处理相应的问题。
2.Java高CPU占用排查步骤
- top:找到占用CPU高的进程PID
- jstack PID >> java_stack.log:导出CPU占用高进程的线程栈
- top -Hp PID:找出PID的进程占用CPU过高的线程tid。(或使用命令 ps -mp PID -o THREAD,tid,time | sort -rn | less)
- printf “%x\n” tid:将需要的线程ID转换为16进制格式。
- less java_stack.log:查找转换成为16进制的线程TID,找到对应的线程栈,分析并处理问题。
3.Java高内存占用排查步骤
- top:找到占用内存(RES列)高的Java进程PID。
- jmap -heap PID:查看heap内存使用情况。
- jps -lv :查看JVM参数配置。
- jstat -gc PID 1000:收集每秒堆的各个区域具体占用大小的gc信息。
- jmap -dump:live,format=b,file=heap_dump.hprof PID :导出堆文件。
- 使用MAT打开堆文件,分析问题。
4.Java堆外内存泄漏排查步骤
- top:找到占用内存(RES列)较高的Java进程PID。
- jstat -gcutil PID 1000 查看每秒各个区域占堆百分比,若gc正常,则分析堆外内存使用情况。
- jcmd PID VM.native_memory detail,该命令需要添加JVM参数 -XX:NativeMemoryTracking=detail,并重启Java进程才能生效,该命令会显示内存使用情况,查看输出结果,总的committed的内存是否小于物理内存(RES),因为jcmd命令显示的内存包含堆内内存、Code区域、通过unsafe.allocateMemory和DirectByteBuffer申请的内存,但是不包含其他Native Code(C代码)申请的堆外内存。
- pmap -x PID | sort -rn -k 3:查看内存分布,是否有地址空间不在jcmd命令所给出的地址空间中。
- 用工具定位堆外内存,如gperftools、gdb、strace等。
\