【4.2】jdk命令行工具
1、jps:虚拟机进程状况工具;
C:\Users\pacoson>jps -l // 输出主类名称
12272 sun.tools.jps.Jps
12736 chapter3.Page93
2808
C:\Users\pacoson>jps -v // 查看虚拟机进程启动时的参数
12736 Page93 -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -Dfile.encoding=UTF-8
2808 -Dosgi.requiredJavaVersion=1.6 -Xms40m -Xmx512m -Dgrails.console.enable.interactive=false -Dgrails.console.enable.terminal=false -Djline.terminal=jline.UnsupportedTerminal -Dgrails.console.class=grails.build.logging.GrailsEclipseConsole
6072 Jps -Dapplication.home=D:\Java\jdk1.8.0_172 -Xms8m
C:\Users\pacoson>jps // 列出正在运行的虚拟机进程
12736 Page93
2808
7992 Jps
补充:
jps -q 仅输出本地虚拟机唯一id, LVMID;
jps -m 输出虚拟机启动时传递给主类的main函数的参数;
jps可以通过rmi 协议查看开启了rmi服务的远程虚拟机进程状态 ;
2、jstat:虚拟机统计信息监视工具(java statistics monitoring tool)
C:\Users\pacoson>jstat -gcutil 12736 1000 20 // 每隔1000毫秒查看虚拟机12736的内存使用率,共查看20次
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.421
0.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.421
0.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.421
0.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.421
S0=Survivor0, S=Suivivor1, E=Eden区域, O=Old区域, YGC=Young GC=收集年轻代次数=6, YGCT=0.015秒(年轻代收集耗时), FGC=Full GC=老年代收集次数=8, FGCT=Full GC Time=老年代收集耗时=0.421;
3、jinfo:java配置信息工具: 实时查看和调整虚拟机各项参数;
C:\Users\pacoson>jps // 查看本地java虚拟机id
12736 Page93
11496 Jps
2808
C:\Users\pacoson>jinfo -flags //查看虚拟机参数
Usage:
jinfo [option]
(to connect to running process)
jinfo [option]
(to connect to a core file)
jinfo [option] [server_id@]
(to connect to remote debug server)
where
4、jmap:java内存映像工具,用于生成堆转储快照文件,一般称为heapdump 或 dump文件(堆转储快照文件);
使用-XX:+HeapDumpOnOutOfMemoryError参数,可以让jvm在oom异常出现之后自动生成dump文件;
jmap在windows平台下的功能是受限的;
jmap和jhat连用以查看虚拟机堆转储快照如下:
5、jhat:虚拟机堆转储快照分析工具;jvm Heap Analysis Tool,与jmap搭配使用;(不推荐使用jhat命令分析dump文件)
推荐的分析堆转储快照工具有:VisualVM, Eclipse Memory Analyzer, IBM HeapAnalyzer等工具;
C:\Users\pacoson>jmap -dump:format=b,file=eclipse.bin 12736 // 生成jvm12736的堆转储快照文件
Dumping heap to C:\Users\pacoson\eclipse.bin ...
File exists
C:\Users\pacoson>
C:\Users\pacoson>jhat eclipse.bin // 启用内嵌web服务器分析eclpse.bin 文件(访问localhost:7000)
Reading from eclipse.bin...
Dump file created Tue May 07 23:43:59 CST 2019
Snapshot read, resolving...
Resolving 7066 objects...
Chasing references, expect 1 dots.
Eliminating duplicate references.
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
6、jstack:java堆栈跟踪工具
jstack=stack trace for java, 用于生成虚拟机当前时刻的线程快照(一般称为threaddump文件或 javacore文件);
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程死锁,死循环,请求外部资源超时等;
C:\Users\pacoson>jstack -l 12736 // 查看12736进程堆栈信息
2019-05-12 20:55:41
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.172-b11 mixed mode):
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x000000001557f000 nid=0x794 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x0000000015505000 nid=0x36e8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000154fe000 nid=0x3ab4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000154f1000 nid=0x32b4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x0000000015499000 nid=0x16e4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000015498000 nid=0x578 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000154ef800 nid=0x5b0 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000015480800 nid=0x2c3c in Object.wait() [0x000000001595f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000fec08a78> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000000fec08a78> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001357d000 nid=0x103c in Object.wait() [0x000000001545f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000fec01158> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000fec01158> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
Locked ownable synchronizers:
- None
"main" #1 prio=5 os_prio=0 tid=0x0000000002f2d800 nid=0x780 waiting on condition [0x0000000002a8f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at chapter3.Page93.minorGC(Page93.java:24)
at chapter3.Page93.main(Page93.java:10)
Locked ownable synchronizers:
- None
"VM Thread" os_prio=2 tid=0x0000000013578000 nid=0x3350 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002df7800 nid=0x3958 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002df9000 nid=0x4a7c runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002dfa800 nid=0xcdc runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002dfc000 nid=0x3a2c runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000002dfe800 nid=0x3b30 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002dff800 nid=0x3a0 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002e02800 nid=0x2a0 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002e05000 nid=0x1ed4 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x00000000155ae000 nid=0x35e8 waiting on condition
JNI global references: 5
可以通过调用 Thread.getAllStackTraces() 方法完成 jstack的大部分功能;
【荔枝】
/**
* Thread.getAllStackTraces获取虚拟机中所有线程的StackTraceElement对象
* , 模拟jstack的大部分功能
*/
public class Page111 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(new Random(17).nextInt(10));
}
}).start(); // // 启动线程
}
for (int i = 0; i < 3600; i++) {
System.out.println("================");
try {
Thread.sleep(1000);
/* Thread.getAllStackTraces获取虚拟机中所有线程的StackTraceElement对象 */
Map stackTracks = Thread.getAllStackTraces();
for (Map.Entry entry : stackTracks.entrySet()) {
System.out.println("key = " + entry.getKey().getName() + ", value = " + entry.getValue());
StackTraceElement[] elements = entry.getValue();
int index = 1;
for (StackTraceElement e : elements) {
System.out.println("value[" + index++ +"] = " + e);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// Thread.getAllStackTraces获取虚拟机中所有线程的StackTraceElement对象,线程方法堆栈信息
key = Finalizer, value = [Ljava.lang.StackTraceElement;@5c647e05
value[1] = java.lang.Object.wait(Native Method)
value[2] = java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
value[3] = java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
value[4] = java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
key = Attach Listener, value = [Ljava.lang.StackTraceElement;@33909752
key = Signal Dispatcher, value = [Ljava.lang.StackTraceElement;@55f96302
key = Reference Handler, value = [Ljava.lang.StackTraceElement;@3d4eac69
value[1] = java.lang.Object.wait(Native Method)
value[2] = java.lang.Object.wait(Object.java:502)
value[3] = java.lang.ref.Reference.tryHandlePending(Reference.java:191)
value[4] = java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
key = main, value = [Ljava.lang.StackTraceElement;@42a57993
value[1] = java.lang.Thread.dumpThreads(Native Method)
value[2] = java.lang.Thread.getAllStackTraces(Thread.java:1610)
value[3] = chapter4.Page111.main(Page111.java:25)
7、HSDIS:JIT生成代码反汇编
HSDIS是一个sun官方推荐的hotspot虚拟机 JIT编译代码的反汇编插件,包含在hotspot虚拟机的源码之中,但没有提供编译后的程序。
作用是让hotspot的-XX:+PrintAssembly 指令调用它来吧动态生成的本地代码还原为汇编代码输出,同时还生成了大量有价值的注释;
【4.3】JDK的可视化工具
JConsole和VisualVM;JConsole是虚拟机监控工具, 而VisualVM是多合一故障处理工具;
1、JConsole:java监视与管理控制台;基于JMX的可视化监视,管理工具;
1.1、启动JConsole;
【JConsole监控荔枝】
/**
* JConsole 监控jvm内存
* vm params: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
*/
public class Page114JConsoleTest {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
for (int i = 0; i < 3600; i++) {
new Thread(new Runnable() {
@Override
public void run() {
byte[] allocation1 = new byte[1 * _1MB];
byte[] allocation2 = new byte[2 * _1MB];
byte[] allocation4 = new byte[4 * _1MB];
}
}).start(); // // 启动线程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1.2、内存监控
/**
* JConsole监视代码
* jvm params: -Xms100m -Xmx100m -XX:+UseSerialGC
* @author tang rong
* 2019/05/12
*/
public class Page117 {
public static void main(String[] args) throws Exception {
fillHeap(1000);
}
public static void fillHeap(int num) throws InterruptedException {
List list = new ArrayList<>();
for (int i=0; i
1.3、线程监控
线程长时间停顿的主要原因有: 等待外部资源(数据库连接,网络资源,设备资源等),死循环,锁等待(活锁和死锁);
【荔枝-线程等待演示代码】
/**
* 线程等待演示代码
* @author tr
* 2019/05/12
*/
public class Page119 {
public static void createBusyThread() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) // 死循环
;
}
}, "testBusyThread").start();
}
public static void createLockThread(final Object lock) {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
try {
lock.wait(); // 线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "testLockThread").start();
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
createBusyThread(); // 死循环
br.readLine();
Object obj = new Object();
createLockThread(obj); // 线程等待
}
}
【荔枝-线程死锁等待演示代码】
/**
* 线程死锁等待演示
* @author tr
* 2019/05/12
*/
public 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)) {
synchronized (Integer.valueOf(b)) {
System.out.println(a+b);
}
}
}
public static void main(String[] args) {
for (int i=0; i<100; i++) {
System.out.println("i = " + i);
new Thread(new SynAddRunnable(1, 2)).start(); // 死锁, 线程1拿到了a锁,准备拿b锁,但线程2拿到了b锁且没有释放;
new Thread(new SynAddRunnable(2, 1)).start(); // 死锁,线程2拿到了b锁,准备拿a锁,但线程1拿到了a锁且没有释放;
}
}
}
出现死锁后,查看线程列表中被阻塞的线程;
【4.3.2】VisualVM:多合一故障处理工具(jvisualvm.exe)
1、VisualVM可以做到:
显示jvm进程配置信息,环境信息(jps, jinfo);
监视cpu, gc,堆,方法区以及线程信息(jstat, jstack);
dump以及分析堆转储快照(jmap,jhat);
方法级的程序运行性能分析,找出被调用最多,运行时间最长的方法;
离线程序快照:收集程序的运行时配置,线程dump,内存dump等信息建立一个快照,可以将快照发送给开发者;
其他plugin的无限可能性;
【补充】VisualVM的兼容性
如果不给VisualVM安装插件,就放弃了其最精华的功能;
2、生成、浏览堆转储快照-dump文件
点击堆dump;
3、分析程序性能:profiler页签中分析;
注意: profiling堆程序运行性能有很大影响,一般不在生产环境做;
4、BTrace动态日志跟踪
4.1、BTrace的作用是:在不停止目标程序运行的前提下,通过hotspot虚拟机的hotswap技术动态加入原本并不存在的调试代码(如日志信息);
补充:hotswap技术,即代码热替换技术, hotspot虚拟机允许在不停止运行的情况下,更新已经加载的类的代码;
/**
* BTrace 跟踪演示
* @date 2019/05/13
*/
public class BTraceTest {
public int add(int a, int b) {
return a + b;
}
public static void main(String[] args) throws IOException {
BTraceTest test = new BTraceTest();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
for (int i = 0; i < 10; i++) {
reader.readLine();
int a = (int) Math.round(Math.random() * 1000);
int b = (int) Math.round(Math.random() * 1000);
System.out.println("test.add(a, b) = " + test.add(a, b));
}
}
}
trace script
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod(
clazz = "chapter4.BTraceTest",
method = "add",
location = @Location(Kind.RETURN)
)
public static void func(@Self chapter4.BTraceTest instance,int a,int b,@Return int result){
println("调用堆栈:");
jstack();
println(strcat("方法参数A:",str(a)));
println(strcat("方法参数B:",str(b)));
println(strcat("方法结果:",str(result)));
}
}
BTrace的用法包括: 打印调用堆栈,参数,返回值只是最基本的应用,还可以进行性能监视,定位连接泄漏和内存泄漏,解决多线程竞争问题等;