1 示例代码
1.1 示例代码1 元空间OOM
设置启动参数:
-XX:+PrintGCDetails -XX:MetaspaceSize=20m -XX:MaxMetaspaceSize=20m
public class MetaspaceOverFlowTest {
public static void main(String[] args) throws InterruptedException {
while (true) {
Thread.sleep(40);
Enhancer enhancer = new Enhancer();
enhancer.setUseCache(false);
enhancer.setSuperclass(MetaspaceOverFlowTest.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, objects);
}
}) ;
Object o = enhancer.create();
// System.out.println(o);
}
}
1.2 示例代码2 堆OOM
设置启动参数
-Xms10m -Xmx10m -XX:+PrintGCDetails
public class HeapOverFlowTest {
int [] intArr = new int[10];
public static void main(String[] args) throws InterruptedException {
List<HeapOverFlowTest> list = new ArrayList<>();
for(;;) {
Thread.sleep(1);
list.add(new HeapOverFlowTest());
}
}
}
1.3 示例代码3 虚拟机栈OOM
启动参数设置:
-Xss200k```
```java
public class StackOverFlowTest {
private int i =0;
public void test() {
i++;
test();
}
public static void main(String[] args) {
StackOverFlowTest stackOverFlowTest = new StackOverFlowTest();
try {
stackOverFlowTest.test();
}catch (Throwable e) {
e.printStackTrace();
System.out.println(stackOverFlowTest.i);
}
}
}
1.4 示例代码4
public class UtilDemo1 {
public static void main(String[] args) {
while (true);
}
}
1.5 示例代码5 死锁
public class DeadLockDemo {
public static String lockA = "Lock A";
public static String lockB = "Lock B";
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println(Thread.currentThread().getName()+"获取到 Lock A 的锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"等待 Lock B 的锁。。。");
synchronized (lockB) {
System.out.println(Thread.currentThread().getName()+"获取到 Lock B 的锁");
}
}
}
},"线程A").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockB) {
System.out.println(Thread.currentThread().getName()+"获取到 Lock B 的锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"等待 Lock A 的锁。。。");
synchronized (lockA) {
System.out.println(Thread.currentThread().getName()+"获取到 Lock A 的锁");
}
}
}
},"线程B").start();
}
}
2 调优工具使用及原理
2.1 PerfData文件
jvm 启动的时候会创建PerfData文件,记录一些数据。Windows下默认路径是C:\Users\username\AppData\Local\Temp\hsperfdata_username,Linux下默认路径是/tmp/hsperfdata_username。
2.1.1 文件创建
取决于两个参数
-XX:-/+UsePerfData
默认是开启的
关闭方式:-XX:-UsePerfData。如果关闭了,就不会创建PerfData文件
-XX:-/+PerfDisableSharedMem(禁用共享内存)
默认是关闭的,即支持内存共享。如果禁用了,依赖于PerfData文件的工具就无法正常工作了
2.1.2 文件删除
默认情况下随Java进程的结束而销毁,但是如kill -9,这种信号jvm是不能捕获的,所以导致进程直接退出了,而没有做一些收尾性的工作,这个时候你会发现进程虽然没了,但是这个文件其实还是存在的;jvm里考虑到了这种情况,会在当前用户接下来的任何一个java进程(比如说我们执行jps)起来的时候会去做一个判断,看/tmp/hsperfdata_下的进程是不是还存在,如果不存在了就直接删除该文件,判断是否存在的具体操作其实就是发一个kill -0的信号看是否有异常。
2.1.3 文件更新
-XX:PerfDataSamplingInterval = 50ms
即内存与PerfData文件的数据延迟为50ms
2.2 jps
jps -q 只显示java进程的ID
jps -l 输出Java进程的ID + main函数所在类的全限定名(包名 + 类名)
jps -m 输出Java进程的ID + main函数所在类的名词 + 传递给main函数的参数
jps -v 输出Java进程的ID + main函数所在类的名称 + 传递给JVM的参数
2.2.1 原理
源码路径:
tools.jar\sun\tools\jps\
JPS的原理是读取取PerfData文件获取信息。
2.2.2 实战
2.2.2.1 jps -q
直接运行示例代码1,使用命令
输出了所有java进程的ID
2.2.2.2 jps -l
输出java进程ID+main函数所在类的全限定名。
2.2.2.3 jps -m
运行示例代码1,并给main函数添加参数
输出 java进程ID +main函数所在类名称+main函数的参数
2.2.2.4 jps -v
运行示例代码1,并给添加jvm参数
输出java进程ID + main函数所在类名称 + jvm 参数。
2.2.2.5 组合使用 jps -lv
输出java进程ID + main函数所在类全限定名 + jvm 参数。
2.3 jstat
jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。
2.3.1 原理
源码路径:
tools.jar\sun\tools\jstat\
jstat 输出的每一列定义在tools.jar\sun\tools\jstat\resources\jstat_options文件中。
文件内容如上图,定义了用途和计算方式,其中如java.cls.loadedClasses这类变量是读取的PerfData文件里的内容。
2.3.2 实战
jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]
2.3.2.1 jstat -options
获取所有的命令参数
2.3.2.2 jstat -class PID
输出类加载信息。
运行实例代码1
使用jps查出进程ID,然后使用jstat -class 进程ID,查询类加载信息。
各列信息为:
Loaded 装载的类的数量
Bytes 装载类所占用的字节数
Unloaded 卸载类的数量
Bytes 卸载类的字节数
Time 装载和卸载类所花费的时间
jstat 命令还可设置间隔输出,输出几次,比如
上图为每2秒输出一次,共输出5次。
2.3.2.3 jstat -compiler PID
输出JVM即时编译的信息。
运行示例代码4
各列信息:
Compiled 编译任务执行数量
Failed 编译任务执行失败数量
Invalid 编译任务执行失效数量
Time 编译任务消耗时间
FailedType 最后一个编译失败任务的类型
FailedMethod 最后一个编译失败任务所在的类及方法
2.3.2.4 jstat -gc PID
输出gc的信息,查看gc的次数,及时间。
运行示例代码1
各列信息:
S0C 年轻代survivor1的容量
S1C 年轻代urvivor2的容量
S0U 年轻代survivor1目前已使用空间
S1U 年轻代survivor2目前已使用空间
EC 年轻代Eden的容量
EU 年轻代Eden目前已使用空间
OC 老年代的容量
OU Old代目前已使用空间
MC 元空间容量
MU 元空间目前已使用空间
CCSC 压缩类空间大小
CCSU 压缩类空间使用大小
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间
FGC 从应用程序启动到采样时full gc次数
FGCT 从应用程序启动到采样时full gc所用时间
GCT 从应用程序启动到采样时gc用的总时间
2.3.2.5 jstat -gccapacity PID
输出年轻代、老年代、元空间信息
运行示例代码1
各列信息:
NGCMN 年轻代初始化大小
NGCMX 年轻代最大容量
NGC 年轻代当前的容量
S0C survivor1的容量
S1C survivor2的容量
EC Eden的容量
OGCMN 老年代中初始化大小
OGCMX 老年代的最大容量
OGC 老年代当前容量
OC 老年代当前容量
MCMN 元空间最小容量
MCMX 元空间最大容量
MC 当前元空间大小
CCSMN 最小压缩类空间大小
CCSMX 最大压缩类空间大小
CCSC 当前压缩类空间大小
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时full gc次数
2.3.2.6 jstat -gccause PID
输出最近一次gc统计和原因
运行示例代码1
各列信息:
// 使用率 = (已使用/总容量)*100%
S0 survivor1使用率
S1 survivor2使用率
E Eden使用率
O 老年代使用率
M 元空间使用率
CCS 压缩类空间使用率
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间
FGC 从应用程序启动到采样时full gc次数
FGCT 从应用程序启动到采样时full gc所用时间
GCT 从应用程序启动到采样时gc用的总时间
LGCC 最后一次GC原因
GCC 当前GC原因
2.4.2.7 jstat -gcmetacapacity PID
输出元空间信息
运行示例代码1
各列信息:
MCMN 元空间初始容量
MCMX 元空间最大容量
MC 当前元空间容量
CCSMN 压缩类空间初始容量
CCSMX 压缩类元空间最大容量
CCSC 当前压缩类容量
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时full gc次数
FGCT 从应用程序启动到采样时full gc所用时间
GCT 从应用程序启动到采样时gc用的总时间
2.3.2.8 jstat -gcnew PID
年轻代信息
运行示例代码1
各列信息:
S0C survivor1的容量
S1C survivor2的容量
S0U survivor1目前已使用空间
S1U survivor2目前已使用空间
TT 持有次数限制
MTT 最大持有次数限制
EC Eden的容量
EU Eden目前已使用空间
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间
2.3.2.9 jstat -gcnewcapacity PID
输出年轻代容量信息
运行示例代码2
NGCMN 年轻代初始化容量
NGCMX 年轻代的最大容量
NGC 年轻代当前的容量
S0CMX survivor1的最大容量
S0C survivor1当前的容量
S1CMX survivor2的最大容量
S1C survivor2当前的容量
ECMX Eden的最大容量
EC Eden的当前容量
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时full gc次数
2.3.2.10 jstat -gcold
输出老年代信息
运行示例代码2
各列信息:
MC 元空间容量
MU 元空间使用容量
CCSC 压缩类空间容量
CCSU 压缩类空间使用容量
OC 老年代的容量
OU 老年代目前已使用容量
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时full gc次数
FGCT 从应用程序启动到采样时full gc所用时间
GCT 从应用程序启动到采样时gc用的总时间
2.3.2.11 jstat -gcoldcapacity PID
输出老年代容量信息
运行实例代码2
各列信息:
OGCMN 老年代初始化容量
OGCMX 老年代的最大容量
OGC 老年代当前容量
OC 老年代的容量
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时full gc次数
FGCT 从应用程序启动到采样时full gc所用时间
GCT 从应用程序启动到采样时gc用的总时间
2.3.2.12 jstat -gcutil PID
输出gc统计信息
运行示例代码2
各列信息:
// 使用率 = (已使用/总容量)*100%
S0 survivor1使用率
S1 survivor2使用率
E Eden使用率
O 老年代使用率
M 元空间使用率
CCS 压缩类空间使用率
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间
FGC 从应用程序启动到采样时full gc次数
FGCT 从应用程序启动到采样时full gc所用时间
GCT 从应用程序启动到采样时gc用的总时间
2.3.2.13 jstat -printcompilation PID
输出当前jvm执行信息
运行示例代码2
各列信息:
Compiled 编译任务的数量
Size 方法生成的字节码的大小
Type 编译类型
Method 类名和方法名用来标识编译的方法。类名使用/做为一个命名空间分隔符。方法名是给定类中的方法。上述格式是由-XX:+PrintComplation选项进行设置的
2.4 jstack
打印给定java进程ID的堆栈信息,即java虚拟机当前时刻的线程快照,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
源码路径:
tools.jar\sun\tools\jstack\
2.4.1 实战
-l 除堆栈外,打印额外的锁信息,发生死锁用这个来观察。
-F 正常输出的请求未响应时,强制输出线程堆栈。
-m 如果调用到本地方法的话,可以打印C/C++的堆栈
-h 帮助信息
2.4.1.1 jstack -l PID
运行示例代码5
上图为jstack 输出的部分信息,可以看出:
线程A锁住了0x00000000d5ef58d0在等待0x00000000d5ef5908
线程B锁住了0x00000000d5ef5908在等待0x00000000d5ef58d0
上图为jstack 输出部分信息,可以已看出:已经明确是输出发现了一个java级别的死锁。
2.3.1.2 jstack -F PID
正常输出的请求未响应时,使用这个命令强制输出。
2.3.1.3 jstack -m PID
调用到本地方法的话,可以打印C/C++的堆栈。
2.5 jinfo
用于打印配置信息,包括命令行参数、系统变量。极少数的情况下,我们可以用其来修改命令行参数。
jinfo -flags PID 查看JVM参数 如-Xms -Dfile.encoding=GBK
jinfo -flags +/- name PID 用于开启或关闭虚拟机标记参数。+表示开启,-表示关闭,有+或-表示设置,没有+或-就是打印参数。如jinfo -flags +PrintGC PID
jinfo -flags name=value PID 设置虚拟机参数 ,并不是每个参数都可以设置。如:jinfo -flags HeapDumpPath PID 设置dump日志路径
jinfo -sysprops PID 查看系统参数 System.getProperty(key);
2.5.1 实战
2.5.1.1 jinfo -flags PID
查看jvm参数
运行示例代码2
设置参数
2.5.1.2 jinfo -flags +/- name PID
用于开启或关闭布尔类型虚拟机标记参数。+表示开启,-表示关闭,有+或-表示设置,没有+或-就是打印参数。
以PrintGC为例
运行示例代码2
2.5.1.3 jinfo -flags name=value PID
设置字符串和数字类型虚拟机参数 ,并不是每个参数都可以设置。如:jinfo -flags HeapDumpPath PID 设置dump日志路径。
2.5.1.4 jinfo -sysprops PID
查看系统参数 System.getProperty(key);
运行示例代码2 设置系统参数
2.6 jmap
输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。
jmap -dump:live,fomat=b,file=dump.hprof PID 打印当前dump堆到文件,format指定输出格式,live指明是活着的对象,file指定文件名。文件可用VisualVM打开,可查看类的实例数量和大小。
jmap -heap PID 打印heap的概要信息,GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况。
jmap -finalizerinfo PID 打印正等候回收的对象的信息。
jmap -histo:live PID 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”.
如果live子参数加上后,只统计活的对象数量. 这个命令执行,jvm会先触发GC,然后再统计信息。
jmap -clstats PID 打印Java类加载器的智能统计信息,对于每个类加载器而言,它的名称,活跃度,地址,父类加载器,它所加载的类的数量和大小都会被打印。此外,包含的字符串数量
和大小也会被打印。-F 强制模式。如果指定的pid没有响应时使用;如:jmap -F -histo 129665
2.6.1 实战
2.6.1.1 jmap -dump:live,fomat=b,file=dump.hprof PID
打印当前dump堆到文件,format指定输出格式,live指明是活着的对象,file指定文件名。文件可用VisualVM打开,可查看类的实例数量和大小。
运行示例代码2
在jvm-demo1目录下生成了heap.hprof文件
打开jvisual VM
点击文件 --> 装入 ,选择刚刚生成的文件。
首页是一些概要信息,如加载类总数、实例总数。
点击类这个选项卡可以看出int[]实例数最多,并且所占容量最大,双击这行。
可以看到大部分引用都是来自HeapOverFlowTest.intArr,所以如果是内存泄漏的话,可以根据这种方式来定位问题。
我们可以在启动jvm的时候添加参数-XX:+HeapDumpOnOutOfMemoryError,再发生Heap的OOM的时候会自动生成堆的dump文件。
2.6.1.2 jmap -heap PID
打印heap的概要信息,GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况。
运行代码示例2
上图为各部分的容量大小。
上图为各部分的使用情况。
2.6.1.3 jmap -finalizerinfo PID
打印正等候回收的对象的信息。
上图可以看出值为0没有要回收的对象。
2.6.1.4 jmap -histo:live PID
打印每个class的实例数目,内存占用,类全名信息. JVM的内部类名字开头会加上前缀”*”。live 表示存活对象。
运行实例代码2
各列信息:
num 编号id
instances 实例个数
bytes 所有实例大小
class name 类名
2.6.1.5 jmap -clstats PID
打印Java类加载器的智能统计信息,对于每个类加载器而言,它的名称,活跃度,地址,父类加载器,它所加载的类的数量和大小都会被打印。此外,包含的字符串数量
和大小也会被打印。
运行示例代码2
各列信息
class_loader 类加载器实例
classes 加载类数量
bytes 加载类大小
parent_loader 父类加载器
alive 是否存活
type 类加载器类型
2.6.1.6 -F强制模式
如果指定的pid没有响应时使用;如:jmap -F -histo 129665
2.7 jconsole
jconsole是jdk自带的基于JMX的可视化监视、管理工具。
2.7.1 启动
jconsole 位于 JAVA_HOME/bin/jconsole.exe 目录。
现在运行示例代码1
找到你需要监控的进程,连接。
上图为概览页面,可以看出一共分为概览、内存、线程、类、VM概要、Mbean6各模块。
2.7.2 概览
显示内存使用率,线程数,Java VM中加载的类数量、CPU使用率的监控信息。
2.7.3 内存
显示了运行时内存各部分的使用信息,如下图可以选择堆、老年代、Eden等。
2.7.4 线程
显示线程有关信息
运行示例代码5
如上图显示了线程A锁定了java.lang.String@330ce8a5,现在时状态:BLOCKED,
获取java.lang.String@7af45c69的锁阻塞了, 拥有者: 线程B
点击检查死锁
可以看到线程A和线程B死锁了。
2.7.5 类
现在类加载信息
2.7.6 VM 概要
VM概要显示了虚拟机信息,运行时间、编译器、线程、类加载等、classpath、堆、垃圾收集器等等.
2.7.8 MBean
2.7.9 远程连接
远程连接,必须配置JMX连接参数。
-Djava.rmi.server.hostname=host #远程服务器ip,即本机ip
-Dcom.sun.management.jmxremote #允许JMX远程调用
-Dcom.sun.management.jmxremote.port=port #自定义jmx 端口号
-Dcom.sun.management.jmxremote.ssl=false # 是否需要ssl 安全连接方式
-Dcom.sun.management.jmxremote.authenticate=false #是否使用用户名和密码验证,此处也选择false
再启动jvm时加入以上参数;
tomcat的配置是在catalina.sh文件里的最后一个JAVA_OPTS的赋值语句下一行增加一行
JAVA_OPTS="$JAVA_OPTS ‐Dcom.sun.management.jmxremote.port=8888 …",把上述的几个配置项都添加进去。
2.8 jvsiualvm
jvsiualvm是jdk自带的监控工具,可以监控内存泄露,跟踪垃圾回收,执行时内存、cpu分析,线程分析等,几乎包含上面介绍的所有监控命令的功能。
位于JAVA_HOME/bin/jvisiualvm.exe
2.8.1 启动
启动示例代码2
如果启动了java进程,可以再本地找到java进程。
双击进程
可以看到有概述、监视、线程、抽样器、Profiler、Visual GC(通过插件自己安装)
2.8.2 概述
可以看到显示了虚拟机信息,和JVM参数 ,系统属性。
2.8.3 监视
显示了CPU使用率、元空间、堆内存的使用,类加载数量,线程信息。
点击堆dump ,可以查看堆的快照信息,显示实例数量等信息。
点击类选项卡
上图位类选项卡的显示的信息,显示类的实例数量和所占空间大小,双击红框中的类,如下图,显示了实例种的引用信息,和被引用的信息。
2.8.4 线程
显示线程的名称和运行的状态,也可显示死锁信息,可以点进一个线程查看这个线程的详细运行情况
运行示例代码5
点击上图的堆dump,可以显示线程详细信息。
2.8.5 抽样器
显示CPU和内存使用情况
CPU:
内存:
2.8.6 Visual GC
显示jvm内存各部分使用情况
2.8.7 远程连接
远程连接,必须配置JMX连接参数。
-Djava.rmi.server.hostname=host #远程服务器ip,即本机ip
-Dcom.sun.management.jmxremote #允许JMX远程调用
-Dcom.sun.management.jmxremote.port=port #自定义jmx 端口号
-Dcom.sun.management.jmxremote.ssl=false # 是否需要ssl 安全连接方式
-Dcom.sun.management.jmxremote.authenticate=false #是否使用用户名和密码验证,此处也选择false
填写IP地址点击确定。
2.8.8 导入堆的dump文件
运行示例代码2,添加参数-XX:+HeapDumpOnOutOfMemoryError,发生堆OOM时候保存堆的快照信息。
启动后等待OOM后再项目跟目录下找到快照文件
导入文件,选择文件 --> 装入
如何使用查看本篇2.6.1.1章节。
2.9 arthas
Arthas(阿尔萨斯)是阿里巴巴开源的 Java 诊断工具。
下载路径:https://github.com/alibaba/arthas/releases
2.9.1 启动
java -jar arthas-boot.jar
运行示例代码1
输入前面的序号进入进程
2.9.2 dashboard
显示当前的线程信息,内存使用情况。
表格中各列信息说明:
ID Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应。
NAME 线程名
GROUP 线程组名
PRIORITY 线程优先级, 1~10之间的数字,越大表示优先级越高
STATE 线程的状态
CPU% 线程的cpu使用率。比如采样间隔1000ms,某个线程的增量cpu时间为100ms,则cpu使用率=100/1000=10%
DELTA_TIME 上次采样之后线程运行增量CPU时间,数据格式为秒
TIME 线程运行总CPU时间,数据格式为分:秒
INTERRUPTED 线程当前的中断位状态
DAEMON 是否是daemon线程
线程信息下方是jvm运行时内存各部分使用情况
还可对命令添加参数:
dashboard -i1000 -n3
-i 每多少ms刷新一次
-n一共刷新几次
2.9.3 thread
查看当前线程信息,查看线程的堆栈
thread -n 3 指定最忙的前N个线程并打印堆栈
thread -b 找出当前阻塞其他线程的线程
thread -i 指定cpu使用率统计的采样间隔,单位为毫秒
运行示例代码5
2.9.3.1 中文乱码解决
上图种可以看到我们线程的中文名字乱码了,需要在启动的时指定字符集
java -jar -Dfile.encoding=UTF-8 arthas-boot.jar
可以看到中文显示正常。
2.9.3.2 thread id
显示指定id线程的堆栈信息,如打印线程A的堆栈,线程A的ID 为12
2.9.3.3 thread -b
找出当前阻塞其他线程的线程,目前只支持找出synchronized关键字阻塞住的线程, 如果是java.util.concurrent.Lock, 目前还不支持。
2.9.3.4 thread -n
当前最忙的前N个线程并打印堆栈
2.9.3.5 thread -i
指定采样时间间隔,如:
thread -i 1000 : 统计最近1000ms内的线程CPU时间。
thread -n 3 -i 1000 : 列出1000ms内最忙的3个线程栈
2.9.3.6 thread –state
查看指定状态的线程,如
thread -state BLOCKED 查看阻塞状态的线程
2.9.4 sysprop
查看和修改JVM的系统属性
2.9.4.1 sysprop
查看所有属性
2.9.4.2 sysprop key
查看单个属性
2.9.4.3 sysprop key value
修改单个属性
2.9.5 vmoption
查看,更新VM诊断相关的参数,如打印堆dump,是否打印gc信息,修改堆扩容的空闲堆比例等。
2.9.5.1 vmoption
查看所有的option
2.9.5.2 vmoption key
查看指定的option
2.9.5.3 vmoption key value
更新指定的option
2.9.6 getstataic
查看类的静态属性
使用方法为
getstatic class_name field_name
2.9.7 ognl
执行ognl表达式
如:
ognl ‘@java.lang.System@out.println(“hello arthas”)’ 调用静态函数,输出在日志中或控制台
2.9.8 heapdump
打印当前dump堆到文件,如:
heapdump /tmp/dump.hprof
heapdump --live /tmp/dump.hprof 只要活的对象
hprof文件的查看,请看上文2.8.8
2.10 HSDB
HSDB(Hotspot Debugger),JDK自带的工具,用于查看JVM运行时的状态。
HSDB位于JAVA_HOME\lib\sa-jdi.jar里面
启动命令:
java -cp .\sa-jdi.jar sun.jvm.hotspot.HSDB
启动后界面如下:
2.10.1 连接java进程
找到java进程ID
2.10.2 查看线程堆栈信息
2.10.3 查看类加载信息
显示了jvm加载的所有的类,找到我们自己的类,
该类元信息实例InstanceKlass实例的内存地址
上图输入内存地址,查看类的元信息。
2.10.4 查看堆中的实例
上图中显示了各类型的实例数量和实例总大小。
以上仅是目前对这些工具粗浅的使用,以后深入理解后会继续更新完善。
参考连接:
https://blog.csdn.net/shudaqi2010/article/details/53607627
https://blog.csdn.net/zhaozheng7758/article/details/8623549