1. 背景
jps: 查看进程信息
jmap: java堆内存映射工具
jstack: Java堆栈跟踪工具
jinfo: Java配置信息工具
jstat: JVM统计信息监视工具
再使用jcmd和jstack时,要注意需要使用和java进程一致的用户才能执行,分析问题
2. jstack 工具分析
2.1 在线分析thread dump的工具
参考文章:www.bilibili.com/video/BV1MZ…
在线分析地址fastthread.io/
程序这么卡,为啥cpu没压力,并没有飚高,是因为状态是 WAITING,TIMED_WAITING,BLOKED的线程不占用CPU
2.2 jstack 定位CPU占用率过高、接口TPS低的线程代码
原因:
1. 复杂的算法导致CPU使用率高,比如加解密算法、序列化操作
2. 代码中存在死循环
3. 大量的logback日志异步写消耗CPU
4. 频繁的fullgc
top命令 ,大写P,进程按照CPU使用率排序,查看COMMAND是java的 进程, 继续查看进程下哪个线程占用CPU最高,命令:top -H -p 4724, 需要将线程id转换成十六进制printf %x 4739,因为在java堆栈中,存储线程id采用的是16进制 jstack 4724 | grep -C 10 1283 --color, 当程序出现故障,一次dump不足以确认问题,建议最好多生成几次dump信息来确定问题的典型性
参考文章:www.bilibili.com/video/BV1VW…
2.3 jstack -l 内容分析
jps -l
jstack pid > stack.log
|-----线程名------| |-线程创建次序-| |是否守护进程| |---线程优先级---| |-------线程 id-------| |-所映射的linux轻量级进程id-| |-------------线程动作--------------|
"Thread-41" #262 prio=5 os_prio=0 tid=0x00007f50c0035800 nid=0x785 waiting on condition [0x00007f50869c9000]
一般我么你会写一个shell脚本来执行整个过程 www.jianshu.com/p/90579ec31…
3. jmap分析
如何查看一个项目 jvm内存分配情况以及使用率,便于为出现的bug进行问题的定位
jps -l
jmap -heap pid
有时间可以研究这张图
在故障定位(oom)和性能分析的时候,经常用到一些文件来帮助我们排查代码问题,这些文件记录了JVM运行期间内存占用、线程执行的情况,就是dump文件
常用的有heap dump 和 thread dump,heap dump记录内存信息, thread dump记录cpu信息的
压测过程中内存分析问题分析常用步骤
1. 使用free -m命令查看内存使用情况,判断内存占比是否过高
2. 使用jstat -gc pid 命令查看GC回收情况,判断是否存在频繁的fullgc
3. 使用jmap命令生成heap dump文件
jmap -dump:live,format=b,file=m.hprof6534 6534
m.hprof6534:导出的文件名称, 6534:进程号
参考文章:www.bilibili.com/video/BV189…
使用jmap -histo pid 查看哪些类的对象占用最多的内存和个数 也可以使用jmap -dump:live, format=b, file= 0617.hprof pid 打印出内存快照
histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. jmap -histo:live pid
jmap -dump:live, format=b, file= 0327.hprof pid> -dump: [live,]format=b,file=filename 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
-dump:[live,]format=b,file=filename 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
3.1. 压测过程中内存分析问题常用步骤
heap dump记录内存信息的,thread dump记录CPU信息的
free -m 查看内存使用情况,判断内存使用是否占比过高
jstat -gc pid: 查看GC回收情况,判断是否存在FULL GC频繁
jstat 可以查看堆内存各部分的使用量
jstat -class
jstat -compiler
jstat -gc pid
S0C: S0 capacity
使用jmap命令生成head dump文件
使用jvisualvm分析dump文件,找出具体的泄露对象
3.2 jmap命令实战
发现大对象 jmap -histo pid
内存的使用情况 jmap -heap pid
堆内存dump jmap -dump:format=b,file=pid_date.log pid
sort -n -k 3 -r histo.log | less
free -m ,top
jmap -dump:live, format=b, file= 0617.hprof pid
线上频繁FULL GC的问题, 到底多久一次算频繁
GC的过程是要STW的,CMS ,G1 采用三色标记法尽量降低了STW的时长,一次FULLGC的耗时在1s左右,一个小时一次FULL GC就算频繁的了,好一点的应用一天不能超过一次
3.4 free -m 命令
- buffers/cache:程序角度上看未使用、可用的内存数。
- buffers/cache:序角度上看已经使用的内存数,这才是程序实实在在用掉的内存数。
4 jinfo 命令
jinfo -flags pid
5. jstat 命令分析
5.1 使用demo
线上分析GC的问题,从容了解服务的GC情况
YGC: 线程启动到现在YGC发生的次数
YGCT: YGC耗费的时间(秒)
CCS: 压缩过的类空间的利用率
jstat -gcutil pid
jstat -gcutil pid 1000 : 每隔1s持续打印数据
jstat -gcutil pid 1000 5: 打印5次
如何计算一次YGC的耗时:17.558s/2402次 = 7.3ms
5.2. 如何打开GC打印日志的配置
-XX:+PrintGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-Xloggc:/path/to/gc.log
JVM重启了,会把之前的GC日志文件覆盖掉
-Xloggc:/path/to/gc-%t.log
-XX:+UseGCLogFileRotation: 配置日志滚动
-XX:GCLogFileSize=1M : 文件大小最大1M
-XX:NumberOfGCLogFiles=5: 最多5个日志文件
5.3. GC网站
6. OOM 怎么解决
首先进行OOM分析,除了程序计数器之外,其余几个运行数据区都有肯能OOM,因此在遇到OOM时能根据异常信息定位到是哪个内存区域发生的内存溢出
虚拟机栈和本地方法栈递归或者线程数太多,这个可以根据报错信息找到相应代码
首先使用jastat -gcutil pid 查看eden, so,s1 以及老年代的内存使用率,还有fullgc、ygc的次数,发现老年代的使用率很大,fullgc次数很大表示对象很大
其次使用jmap -histo:live pid 查看哪些类的对象占用最多的内存和个数
也可以使用jmap -dump:live, format=b, file= 0617.hprof pid 打印出内存快照
-dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.
7. jvm怎么调优
自报家门: 生产环境的机器 8C16G,-Xms12g, -Xmx12g
如果堆内存不够,尝试调整-Xmx和-Xms,代表最大堆内存和初始堆内存,
使用jstat -gcutil pid 查看eden、s0、s1,以及老年代的内存使用率,fullgc ygc的次数,发现老年代的使用率很大,fullgc次数很大表示对象很大,
8. 参考
juejin.cn/post/695790… :很好的总结了,帮助梳理一遍JVM的命令