Jvm 调试分析
JVM 参数
JVM 参数分为三类:标准参数、非标准参数(-X 参数)、高级选项(-XX 参数)
-
标准参数 所有的JVM实现都必须实现这些参数的功能,而且向后兼容; 如: -version、 -help
-
非标准参数 在不同版本的 jvm 中,参数可能会有所不同,可以通过 java -X 查看非标准参数。默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容; 如: 如 -Xms、-Xmx
-
高级选项 此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用,主要用于 JVM 的调优和 debug 操作。 -XX 参数的使用有 2 种方式,一种是 boolean 类型,一种是非 boolean 类型:
boolean 类型格式:-XX:[±] 非 boolean 类型格式:-XX
显示类加载树 TraceClassLoading
jvm 启动时显示类加载树
-XX:+TraceClassLoading
显示JVM 加载的class
在程序运行的时候有多少类被加载! 你可以用 verbose:class 来监视
-verbose:class
输出到文件
java -jar -verbose:class xxx.jar >> LoadedClassList.txt
classpath
-classpath
告知jvm搜索目录名, jar文档名, zip文档名, 之间用分号;分隔; 使用-classpath后jvm将不再使用CLASSPATH中的类搜索路径, 如果-classpath和CLASSPATH都没有设置, 则jvm使用当前路径(.)作为类搜索路径;
jvm搜索类的方式和顺序为: Bootstrap, Extension, User;
Bootstrap中的路径是jvm自带的jar或zip文件, jvm首先搜索这些包文件, 用System.getProperty("sun.boot.class.path")可得到搜索路径;
Extension是位于JRE_HOME/lib/ext目录下的jar文件, jvm在搜索完Bootstrap后就搜索该目录下的jar文件, 用System.getProperty("java.ext.dirs")可得到搜索路径;
User搜索顺序为当前路径., CLASSPATH, -classpath, jvm最后搜索这些目录, 用System.getProperty("java.class.path")可得到搜索路径;
Djava.ext.dirs
添加依赖库查找目录
java -jar yang.jar -Djava.ext.dirs=./lib内存相关参数
-XX:PermSize=64m //方法区分配的初始内存
-XX:MaxPermSize=64m //方法区所能占用的最大内存
-XX:MetaspaceSize //Java8+ 元空间初始大小 (等于原方法区)
-XX:MaxMetaspaceSize// 元空间最大大小
-Xms10240m //堆内存 初始大小
-Xmx10240m //堆内存 最大大小
-Xss128k //线程栈大小
文件编码 Dfile.encoding
java默认字符串转byte[] (String.getBytes() ) 其编码是平台相关的!! 坑
-Dfile.encoding=UTF-8
JVM 分析神器 (arthas)
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
https://arthas.aliyun.com/doc/ https://github.com/alibaba/arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 键入进程编号
# 命令
dashboard命令列表 dashboard - 当前系统的实时数据面板 getstatic - 查看类的静态属性 heapdump - dump java heap, 类似 jmap 命令的 heap dump 功能 jvm - 查看当前 JVM 的信息 logger - 查看和修改 logger mbean - 查看 Mbean 的信息 memory - 查看 JVM 的内存信息 ognl - 执行 ognl 表达式 perfcounter - 查看当前 JVM 的 Perf Counter 信息 sysenv - 查看 JVM 的环境变量 sysprop - 查看和修改 JVM 的系统属性 thread - 查看当前 JVM 的线程堆栈信息 vmoption - 查看和修改 JVM 里诊断相关的 option vmtool - 从 jvm 里查询对象,执行 forceGc
JVM 远程调试
应用启动参数
jdk 5-8:
-Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n
java -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n -jar halo-1.5.3-SNAPSHOT.jar
jdk9以上:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=192.168.40.171:5005 -jar jetlinks-standalone.jar
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=192.168.2.254:5000 -Dfile.encoding=UTF-8 -jar jetlinks-standalone.jar
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5630 -jar halo-1.5.3-m.jar
java -agentlib:jdwp=transport=dt_socket,address=*:5000,server=y,suspend=n -jar jetlinks-standalone.jar
IDE 设置
-
Eclipse 远程调试 设置 Debug configurations⇒Remote Java Application
-
IDEA 远程调试 Run → edit configurations > (左上)+ → Remote JVM Debug
JDK 的自带工具
jsp
jps是java自带的查看java进程的命令, 通过这个命令可以查看当前系统所有运行中的java进程, java包名, jar包名及JVM参数等;
-
查看进程pid及完整包名及main方法参数:
jps -ml -
查看pid及JVM参数:
jps -v
jstack
使用jstack可查看指定进程(pid)的堆栈信息, 用以分析线程情况:
- 打印堆栈信息
jstack -l pid
jstack -l 695701
- 输出结果到日志中
jstack -l pid > /tmp/jstack.log
- jstack检测死锁
jstack pid
Found one Java-level deadlock: … 省略信息 Found 1 deadlock
找出最耗CPU的线程 (for linux)
- 先找出最耗费CPU的进程
ps -Lfp pid或者ps -mp pid -o THREAD, 或者top -Hp pid
TIME列就是各个Java线程耗费的CPU时间, CPU时间最长的是进程ID
- jstack
例如: 21711 其十六进制值为
54ee
执行jstack
jstack 21711 | grep 54ee
jmap
查看堆内存的配置情况及使用情况:
jmap -heap {PID}
查看对象创建数量:
jmap -histo {PID}
查看vm中内存对象的使用和占用大小
jstat -gccapacity {PID}
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
5440.0 78464.0 7296.0 704.0 704.0 5888.0 10944.0 157056.0 14404.0 14404.0 0.0 1062912.0 15744.0 0.0 1048576.0 1920.0 13239 87Dump 内存
jmap -dump:format=b,file={PATH}/jvm_dump.bin {PID}
# `live`选项会触发一次 Full GC,只转储存活的对象 ,也就是说 GC 收不走的对象
jmap -dump:live,format=b,file=heapdump.hprof {PID}这种方式可以用 jvisualvm GUI工具进行内存分析, 或者采用 Eclipse Memory Analysis Tools (MAT)
Eclipse MAT 的分析思路
- 打开堆转储文件后,MAT 通常会提供一个 Leak Suspects Report(泄漏嫌疑报告)。这是一个非常好的起点,它会智能地分析可能的内存问题。
- 查看 Dominator Tree(支配树) 按照 Retained Heap(保留大小)排序,保留大小指的是回收这个对象后能释放的总内存量。找到那些保留大小异常大的对象。
- 分析可疑对象 在支配树中右键点击可疑对象 → Path To GC Roots → exclude weak/soft references 这个操作会显示从该对象到 GC Roots 的完整引用链,并且排除了弱引用和软引用(因为它们不会阻止 GC)。剩下的就是强引用链,这就是导致它无法被回收的“罪魁祸首”!
- 查看 Histogram(直方图)按类名统计实例数量和总大小。看看哪个类的实例数量多得离谱
jconsole
集成以上三个等的 GUI管理工具
keytool
使用JDK自带工具KeyTool 生成自签发证书
keytool -genkey -alias nginx -keypass yang123. -keyalg RSA -keysize 2048 -validity 365 -keystore D:\software\nginx-1.14.2\conf\nginx.jks -storepass yang123.
-keypass yang123.(别名密码) -validity 365 有效期(天) -storepass yang123.(存储密码)
JKS 密钥库使用专用格式; 建议使用 “keytool -importkeystore -srckeystore D:\software\nginx-1.14.2\conf\nginx.jks -destkeystore D:\software\nginx-1 .14.2\conf\nginx.keystore -deststoretype pkcs12” 迁移到行业标准格式 PKCS12;
转为行业标准格式 PKCS12, 然后再用 openssl 提取公钥/私钥
javac 指定lib编译
扩展编译加执行的例子:
javac TestWord.java -cp E:/PROJECTS-OA/jacob/lib/*
java -cp E:/PROJECTS-OA/jacob/lib/*:jacob.jar net.jk.TestWord