②JVM相关调优命令以及工具
2023-05-17 15:44:46 4 举报
AI智能生成
登录查看完整内容
JVM
作者其他创作
大纲/内容
jps
jps -q
输出主函数传入的参数. 下的hello 就是在执行程序时从命令行输入的参数
jps -m
输出jvm参数
jps -v
jps是jdk提供的一个查看当前java进程的小工具, 可以看做是JavaVirtual Machine Process Status Tool的缩写。非常简单实用。
输出到文件
num:序号instances:实例数量bytes:占用空间大小class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
查看
jmap -histo 14660 #查看历史生成的实例jmap -histo:live 14660 #查看当前存活的实例,执行过程中可能会触发一次full gc
①jmap -histo 进程ID
jmap -heap 14660 #查看堆内存信息
②jmap -heap 进程ID
也可以设置内存溢出自动导出dump文件(内存很大的时候,可能会导不出来)-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=./ (路径)
图示
示例代码
使用jvisualvm命令工具导入dump文件查看
③堆内存dump
查看内存信息、实例个数以及内存占用大小
如果使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始 地址、 映射大小以及共享对象文件的路径全称。-heap 打印java heap摘要-histo[:live] 打印堆中的java对象统计信息-clstats 打印类加载器统计信息-finalizerinfo 打印在f-queue中等待执行finalizer方法的对象-dump: 生成java堆的dump文件 dump-options: live 只转储存活的对象,如果没有指定则转储所有对象 format=b 二进制格式 file= 转储文件到
jmp
public class DeadLockTest { private static Object lock1 = new Object(); private static Object lock2 = new Object(); public static void main(String[] args) { new Thread(() -> { synchronized (lock1) { try { System.out.println(\"thread1 begin\"); Thread.sleep(5000); } catch (InterruptedException e) { } synchronized (lock2) { System.out.println(\"thread1 end\"); } } }).start(); new Thread(() -> { synchronized (lock2) { try { System.out.println(\"thread2 begin\"); Thread.sleep(5000); } catch (InterruptedException e) { } synchronized (lock1) { System.out.println(\"thread2 end\"); } } }).start(); System.out.println(\"main thread end\"); }}
\"Thread-1\" 线程名 prio=5 优先级=5tid=0x000000001fa9e000 线程idnid=0x2d64 线程对应的本地线程标识nidjava.lang.Thread.State: BLOCKED 线程状态
图示1
图示2
jvisualvm查看死锁
使用jstack加进程ID查找死锁例如:jstack -l 14660
package com.tuling.jvm;/** * 运行此代码,cpu会飙高 */public class Math { public static final int initData = 666; public static User user = new User(); public int compute() { //一个方法对应一块栈帧内存区域 int a = 1; int b = 2; int c = (a + b) * 10; return c; } public static void main(String[] args) { Math math = new Math(); while (true){ math.compute(); } }}
①使用命令top -p <pid> ,显示你的java进程的内存情况,pid是你的java进程号,比如19663
②按H,获取每个线程的内存情况
③找到内存和cpu占用最高的线程tid,比如19664
注意:这里转换出来的字母是大写的,要转成小写的去查看
④转为十六进制得到 0x4cd0,此为线程id的十六进制表示
⑤执行 jstack 19663|grep -A 10 4cd0,得到线程堆栈信息中 4cd0 这个线程所在行的后面10行,从堆栈中可以发现导致cpu飙高的调用方法
⑥查看对应的堆栈信息找出可能存在问题的代码
步骤
使用jstack找出占用CPU最高的线程堆栈信息
jstack
①查看jvm参数jinfo -flags 进程ID
②查看java系统参数jinfo -sysprops 进程ID
查看正在运行的Java应用程序的扩展参数
jinfo
S0C:第一个幸存区的大小,单位KBS1C:第二个幸存区的大小S0U:第一个幸存区的使用大小S1U:第二个幸存区的使用大小EC:伊甸园区的大小EU:伊甸园区的使用大小OC:老年代大小OU:老年代使用大小MC:方法区大小(元空间)MU:方法区使用大小CCSC:压缩类空间大小CCSU:压缩类空间使用大小YGC:年轻代垃圾回收次数YGCT:年轻代垃圾回收消耗时间,单位sFGC:老年代垃圾回收次数 FGCT:老年代垃圾回收消耗时间,单位sGCT:垃圾回收消耗总时间,单位s
①jstat -gc pid 垃圾回收统计,最常用,评估程序内存使用及GC压力整体情况
NGCMN:新生代最小容量NGCMX:新生代最大容量NGC:当前新生代容量S0C:第一个幸存区大小S1C:第二个幸存区的大小EC:伊甸园区的大小OGCMN:老年代最小容量OGCMX:老年代最大容量OGC:当前老年代大小OC:当前老年代大小MCMN:最小元数据容量MCMX:最大元数据容量MC:当前元数据空间大小CCSMN:最小压缩类空间大小CCSMX:最大压缩类空间大小CCSC:当前压缩类空间大小YGC:年轻代gc次数FGC:老年代GC次数
②jstat -gccapacity pid堆内存统计
S0C:第一个幸存区的大小S1C:第二个幸存区的大小S0U:第一个幸存区的使用大小S1U:第二个幸存区的使用大小TT:对象在新生代存活的次数MTT:对象在新生代存活的最大次数DSS:期望的幸存区大小EC:伊甸园区的大小EU:伊甸园区的使用大小YGC:年轻代垃圾回收次数YGCT:年轻代垃圾回收消耗时间
③jstat -gcnew pid新生代垃圾回收统计
NGCMN:新生代最小容量NGCMX:新生代最大容量NGC:当前新生代容量S0CMX:最大幸存1区大小S0C:当前幸存1区大小S1CMX:最大幸存2区大小S1C:当前幸存2区大小ECMX:最大伊甸园区大小EC:当前伊甸园区大小YGC:年轻代垃圾回收次数FGC:老年代回收次数
④jstat -gcnewcapacity pid新生代内存统计
MC:方法区大小MU:方法区使用大小CCSC:压缩类空间大小CCSU:压缩类空间使用大小OC:老年代大小OU:老年代使用大小YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
⑤jstat -gcold pid老年代内存回收统计
OGCMN:老年代最小容量OGCMX:老年代最大容量OGC:当前老年代大小OC:老年代大小YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
⑥jstat -gcoldcapacity pid老年代内存统计
MCMN:最小元数据容量MCMX:最大元数据容量MC:当前元数据空间大小 CCSMN:最小压缩类空间大小CCSMX:最大压缩类空间大小CCSC:当前压缩类空间大小YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
⑦jstat -gcmetacapacity pid元空间统计
S0:幸存1区当前使用比例S1:幸存2区当前使用比例E:伊甸园区使用比例O:老年代使用比例M:元数据区使用比例CCS:压缩使用比例YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
⑧jstat -gcutil pid
查看堆内存各部分的使用量,以及加载类的数量jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数]注意:使用的jdk版本是jdk8
jstat
一般电商架构可能会使用多级缓存架构,就是redis加上JVM级缓存,可能为了图方便对于JVM级缓存就简单使用一个hashmap,于是不断往里面放缓存数据,但是很少考虑这个map的容量问题,结果这个缓存map越来越大,一直占用着老年代的很多空间,时间长了就会导致full gc非常频繁,这就是一种内存泄漏,对于一些老旧数据没有及时清理导致一直占用着宝贵的内存资源,时间长了除了导致full gc,还有可能导致OOM。这种情况完全可以考虑采用一些成熟的JVM级缓存框架来解决,比如ehcache等自带一些LRU数据淘汰算法的框架来作为JVM级的缓存。
内存泄漏是怎么回事
常用命令
Arthas 是 Alibaba 在 2018 年 9 月开源的 Java 诊断工具。支持 JDK6+, 采用命令行交互模式,可以方便的定位和诊断线上程序运行问题。Arthas 官方文档十分详细,详见:https://alibaba.github.io/arthas
(1)是否有一个全局视角来查看系统的运行状况?(2)为什么 CPU 又升高了,到底是哪里占用了 CPU ?(3)运行的多线程有死锁吗?有阻塞吗?(4)程序运行耗时很长,是哪里耗时比较长呢?如何监测呢?(5)这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?(6)我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?(7)遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?(8)有什么办法可以监控到 JVM 的实时运行状态?
Arthas使用场景得益于 Arthas 强大且丰富的功能,让 Arthas 能做的事情超乎想象。下面仅仅列举几项常见的使用情况,更多的使用场景可以在熟悉了 Arthas 之后自行探索。
用java -jar运行即可,可以识别机器上所有Java进程(我们这里之前已经运行了一个Arthas测试程序,代码见下方)
# github下载arthaswget https://alibaba.github.io/arthas/arthas-boot.jar# 或者 Gitee 下载wget https://arthas.gitee.io/arthas-boot.jar
Arthas使用
①选择进程序号1,进入进程信息操作
②输入dashboard可以查看整个进程的运行情况,线程、内存、GC、运行环境信息
③输入thread可以查看线程详细情况
④输入 thread -b 可以查看线程死锁
⑤输入 jad加类的全名 可以反编译,这样可以方便我们查看线上代码是否是正确的版本
⑥使用 ognl 命令可以查看线上系统变量的值,甚至可以修改变量的值
Arthas查看模拟 CPU 过高模拟线程死锁不断的向 hashSet 集合增加数据
Arthas
工具
JVM调优常用命令&工具
收藏
0 条评论
回复 删除
下一页