基础故障处理工具
JAVA_HOME下的bin目录包含了一系列小工具:
![](https://img.haomeiwen.com/i5029550/1922a6c7c513a800.png)
jps:虚拟机进程状态工具
jps(JVM Process status Tool):可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main函数所在类)名称及这些进程的本地虚拟机唯一ID(LVMID,Local Cirtual Machine Identifier)。
jps [options] [hostid]
$ jps -l
9113 sun.tools.jps.Jps
6491 org.jetbrains.jps.cmdline.Launcher
99501
jps工具主要选项
选项 | 作用 |
---|---|
-q | 只输出LVMID,省略主类的名称 |
-m | 输出虚拟机进程启动时传递给主类main函数的参数 |
-l | 输出主类的全名,如果进程执行的是JAR包,则输出JAR路径 |
-v | 输出虚拟机进程启动时的JVM参数 |
jstat(JVM Statistics MonitoringTool)是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据。
jstat [option vmid [interval[s|ms][count]]]
![](https://img.haomeiwen.com/i5029550/7f8a330bcb99141b.png)
#2个survivor区(S0、S1,表示Survivor0、Survivor1),新生代Eden区(E),老年代(O),元空间(M)。程序运行以来共发生Minor GC(YGC,表示Young GC)1次,总耗时0.005秒;发生Full GC(FGC,表示Full GC)0次,总耗时(FGCT,表示Full GC Time)为0.000秒;所有GC总耗时(GCT,表示GC Time)为0.005秒
$ jstat -gcutil 6491
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 53.08 22.84 0.08 96.59 95.82 1 0.005 0 0.000 0.005
jinfo:Java配置信息工具
jinfo(Configuration Info for Java)的作用是实时查看和调整虚拟机各项参数。
# jinfo [ option ] pid
$ jinfo -flag CMSInitiatingOccupancyFraction 6491
-XX:CMSInitiatingOccupancyFraction=-1
jmap:Java内存映像工具
jmap(Memory Map for Java)命令用来生成堆转储快照(称为heapdump或dump文件)。还可以查询finalize执行队列、Java堆和方法区的详细信息,如空间使用率,当前用的是哪种收集器等。
jmap [ option ] vmid
jmap工具主要选项
![](https://img.haomeiwen.com/i5029550/4b1ba0be0398311e.png)
jmap -dump:format=b,file=eclipse.bin 3500
jhat:虚拟机堆转储快照分析工具
JDK提供jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。jhat内置了一个微型的Http/Web服务器,生成堆转储快照的分析结果后,可在浏览器中查看。因为jhat比较简陋,一般使用更专业的VisualV、Eclipse Memory Analyzer和IBM HeapAnalyzer等工具。
jhat idea.bin
![](https://img.haomeiwen.com/i5029550/558ad84e9ce8e11e.png)
jstack:Java堆栈追踪工具
jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间卡顿的原因,如线程间死锁、死循环、请求外部资源导致长时间挂起等。
jstack [ option ] vmid
![](https://img.haomeiwen.com/i5029550/cb20033569de38f6.png)
jstack -l 6491
2021-06-10 22:10:32
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode):
"Attach Listener" #14 daemon prio=9 os_prio=31 tid=0x00007f8c35979000 nid=0x5707 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
![](https://img.haomeiwen.com/i5029550/2ad1e97d1a105793.png)
可视化故障处理工具
JConsole、JHSDB、VisualVM和JMC
JHSDB:基于服务性代理的调试工具
JHSDB是一款基于服务性代理(Serviceability Agent,SA)实现的进程外调试工具。服务性代理是HotSpot虚拟机中一组用于映射Java虚拟机运行信息的、主要基于Java语言(含少量JNI代码)实现的API集合。
#jps获取进程id,进入java目录并执行命令,进入图形界面,点击File菜单输入进程id进入界面
sudo java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
![](https://img.haomeiwen.com/i5029550/302fed793ff42843.png)
import java.io.IOException;
/**
* staticObj、instanceObj、localObj存放在哪里?
*/
public class JHSDB_TestCase {
static class Test {
static ObjectHolder staticObj = new ObjectHolder();
ObjectHolder instanceObj = new ObjectHolder();
void foo() {
ObjectHolder localObj = new ObjectHolder();
System.out.println("done");//这里设置一个断点
}
}
private static class ObjectHolder {
}
public static void main(String[] args) throws IOException {
Test test = new JHSDB_TestCase.Test();
test.foo();
}
}
JConsole:Java监视与管理控制台
JConsole(Java Monitoring and Management Console)是一款基于JMX(Java Management Extensions)的可视化监视、管理工具。主要功能是通过JMX的MBean(Managed Bean)对系统进行信息收集和参数动态调整。
- 启动JConsole
#进入java安装目录下的bin
jconsole
![](https://img.haomeiwen.com/i5029550/4806aa82af49222a.png)
- 内存监控
内存页签的作用相当于jstat命令,用于监视被收集器管理的虚拟机内存(被收集器直接管理的Java堆和被间接管理的方法区)的变化趋势。
import java.util.ArrayList;
/**
* VM参数:-Xms100m -Xmx100m -XX:+UseSerialGC
* 以64KB/50ms的速度向Java堆中填充数据,一共填充1000次
* 内存占位符对象,一个OOMObject大约占64KB
*/
public class JConsoleTest {
static class OOMObject {
public byte[] placeholder = new byte[64 * 1024];
}
public static void fillHeap(int num) throws InterruptedException {
ArrayList<OOMObject> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
// 稍作延时,令监视曲线的变化更加明显
Thread.sleep(50);
list.add(new OOMObject());
}
System.gc();
}
public static void main(String[] args) throws InterruptedException {
fillHeap(1000);
}
}
在“内存”页签中可以看到内存池Eden区的运行趋势呈现折线状,监视范围扩大至整个堆后,会发现曲线是一直平滑向上增长的。在循环1000次后,执行System.gc()后,虽然整个新生代Eden和Survivor区都基本被清空了,但是代表老年代的柱状图仍然保持峰值状态,说明被填充进堆中的数据在System.gc()方法执行之后仍然存活。
![](https://img.haomeiwen.com/i5029550/124e803016d8cc28.png)
System.gc()之后,空间未被回收是因为list对象仍然存活,fillHeap方法仍然没有退出,因此list对象在System.gc()执行时仍然处于作用域之内。将代码书写在作用域外即可。
import java.util.ArrayList;
/**
* VM参数:-Xms100m -Xmx100m -XX:+UseSerialGC
* 以64KB/50ms的速度向Java堆中填充数据,一共填充1000次
* 内存占位符对象,一个OOMObject大约占64KB
*/
public class JConsoleTest {
static class OOMObject {
public byte[] placeholder = new byte[64 * 1024];
}
public static void fillHeap(int num) throws Exception {
ArrayList<OOMObject> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
// 稍作延时,令监视曲线的变化更加明显
Thread.sleep(50);
list.add(new OOMObject());
}
// System.gc();
}
public static void main(String[] args) throws Exception {
fillHeap(1000);
System.gc();
System.in.read();
}
}
- 线程监控
"线程"页签相当于可视化的jstack命令。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class BusyAndLockThreadTest {
/**
* 线程死循环演示
*/
public static void createBusyThread() {
new Thread(() -> {
while (true);//41行
}, "testBusyThread").start();
}
/**
* 线程锁等待演示
* @param lock
*/
public static void createLockThread(final Object lock) {
new Thread(() -> {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "testLockThread").start();
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
createBusyThread();
br.readLine();
Object lock = new Object();
createLockThread(lock);
// System.in.read();
}
}
![](https://img.haomeiwen.com/i5029550/9834e1e466745bc8.png)
![](https://img.haomeiwen.com/i5029550/3bf5b8cb58bb2e16.png)
![](https://img.haomeiwen.com/i5029550/4d8acbd3500ea0dc.png)
//Integer.valueOf(a)会对数值为-128-127的Integer对象缓存,容易发生死锁
public class DeadLockTest {
static class SynAddRunnable implements Runnable {
int a, b;
public SynAddRunnable(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (Integer.valueOf(a)) {
System.out.println(a + b);
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10000; i++) {
new Thread(new SynAddRunnable(1, 2)).start();
new Thread(new SynAddRunnable(2, 1)).start();
}
}
}
VisualVM:多合-故障处理工具
VisualVM(All-in-One Java Troubleshooting Tool)是功能最强大的运行监视和故障处理程序之一。
VisualVM兼容范围与插件安装
-
显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)
-
监视应用程序的处理器、垃圾收集、堆、方法区以及线程的信息(jstat、jstack)
-
dump 以及分析堆转储快照(jmap 、jhat )
-
方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法
-
离线程序快照:收集程序的运行时配置、线程dump 、内存dump 等信息建立一个快照,可以将快 照发送开发者处进行Bug反馈
- 生成、浏览堆转储快照
-
堆dump方式
堆dump方式
-
堆dump后分析
-
分析程序性能
Java Mission Control:可持续在线的监控工具
#进入java安装目录,执行jmc
![](https://img.haomeiwen.com/i5029550/49c5fa49b74ff637.png)
可远程连接
![](https://img.haomeiwen.com/i5029550/bf66e3408bb1ebe5.png)
源自书籍:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)-周志明
网友评论