Jconsole

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.ArrayList;
import java.util.List;
public class HelloGC {
byte[] a = new byte[1024 * 100]; //100kb

public static void main(String[] args) throws InterruptedException {

List list = new ArrayList();
while (true) {
list.add(new HelloGC());
Thread.sleep(100);
}

}
}

image-20200828221609446

双击本地HeoolGC然后选择不安全连接

image-20200828221647059


作用: 查看Java应用程序的运行概况,监视垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势,以及监控程序内的线程。

启动JConsole,在控制台输入:jconsole即可,在弹出的界面中,选择本地进程,然后进去看界面页签信息。显示的是整个虚拟机主要运行数据的概览,其中包括堆内存使用情况,线程,类,CPU使用情况四项信息的曲线图。

进来之后有很多标签的,先看默认的第一个概览

概览是对整个Jconsole功能进行一个简述其余几个是对概览的详细解释

image-20200828222348574

内存

相当于命令行的jstat命令,用于监视受垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势,这不仅是包括堆内存的整体信息,更细化到伊甸区、幸存区、老年代的使用情况。同时,也包括非堆区,即元空间的使用情况,单机界面右上角的“执行GC”按钮,可以强制应用程序进行一次Full GC。

image-20200828222457240

可以自己切换查看伊甸园区 老年代 非堆(元空间)的内存使用情况

image-20200828222743005

线程:

相当于命令行的jstack命令,遇到线程停顿的时候可以使用它来进行监控分析。JConsole 显示了系统内的线程数量,并在屏幕下方,显示了程序中所有的线程。单击线程名称,便可以查看线程的栈信息。

image-20200828223128644

类:

如图所示,显示了系统以及装载的类数量。在详细信息栏中,还显示了已卸载的类数量。

image-20200828223208143

VM摘要:

在VM摘要页面,JConsole 显示了当前应用程序的运行环境。包括虚拟机类型、版本、堆信息以及虚拟机参数等。相当于jinfo命令

image-20200828223359188

MBean:

MBean页面允许通过JConsole访问已经在MBean服务器注册的MBean对象。

Jconsole动态监控

上面已经讲解了Jconsole的基本使用,下面我们就通过Jconsole动态监控一下程序的运行状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//每次回车切换一种状态
import java.io.IOException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
JConsole演示线程监控
*/
public class Demo09 {
public static void main(String[] args) throws IOException {
System.in.read();
System.out.println("开启了死循环线程");
whileTrueThread();

System.in.read();
System.out.println("开启了等待线程");
waitThread(new Object());


System.in.read();
System.out.println("开启了死锁线程");
deadLock();

System.in.read();
}

private static void whileTrueThread() {
new Thread(() -> {
while (true) ;
}, "whileTrueThread").start();
}

private static void waitThread(Object o) {
new Thread(() -> {
synchronized (o) {
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"myWaited").start();
}

private static void deadLock() {
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
new Thread(() -> {
try {
lock1.lock();
Thread.sleep(100);
lock2.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "myThread1").start();
new Thread(() -> {
try {
lock2.lock();
Thread.sleep(100);
lock1.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "myThread2").start();
}
}

这是初始状态

image-20200828225818103

当控制台输入一个回车 开启死循环时

CPU直接飙升到25%不下降(因为我4核4线程 所以会到25% 如果是8线程应该是12%左右,当然如果虚拟机单核的 直接97%+)

image-20200828224725515

当再次回车时候开启等待线程

这是未按回车的时候(未开启等待线程)

image-20200828225000092

这是按回车的时候(开启等待线程)会多了一个myWaited线程

image-20200828225049973

再次会车开启死锁线程

会再次多出两个线程 状态waiting

image-20200828225235412

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
名称: myThread2
状态: java.util.concurrent.locks.ReentrantLock$NonfairSync@5b103b9b上的WAITING, 拥有者: myThread1
总阻止数: 0, 总等待数: 2

堆栈跟踪:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
cn.itcast.un.Demo09.lambda$deadLock$3(Demo09.java:64)
cn.itcast.un.Demo09$$Lambda$10/1265094477.run(Unknown Source)
java.lang.Thread.run(Thread.java:748)

点击检测死锁时,会检测出来

image-20200828225414413