JVM调优用到的具体命令

258 阅读6分钟

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

image.png

image.png

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情况

image.png

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网站

gceasy.io/

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的命令