简介
本文介绍Java调试相关的命令。
jps
简介
查看基于HotSpot的JVM里面中,所有具有访问权限的Java进程的具体状态, 包括进程ID,进程启动的路径及启动参数等。
jps命令等价于:ps -ef|grep java
格式
jps [ options ] [ hostid ]
如果没有指定hostid,它只会显示本地环境中所有的Java进程;如果指定了hostid,它就会显示指定hostid上面的java进程,不过这需要远程服务上开启了jstatd服务。
示例
jps -l;
选项
选项 | 含义 |
-q | 忽略输出的类名、Jar名以及传递给main方法的参数,只输出pid。 |
-m | 输出传递给main方法的参数,如果是内嵌的JVM则输出为null。 |
-l | 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径。 |
-v | 输出传给JVM的参数。 |
-V | 输出通过标记的文件传递给JVM的参数(.hotspotrc文件,或者是通过参数-XX:Flags=<filename>指定的文件)。 |
-J | 用于传递jvm选项到由javac调用的java加载器中,例如,“-J-Xms48m”将把启动内存设置为48M,使用-J选项可以非常方便的向基于Java的开发的底层虚拟机应用程序传递参数 |
hostid
hostid指定了目标的服务器,它的语法如下:
[protocol:][[//]hostname][:port][/servername]
- protocol – 如果protocol及hostname都没有指定,那表示的是与当前环境相关的本地协议,如果指定了hostname却没有指定protocol,那么protocol的默认就是rmi。
- hostname – 服务器的IP或者名称,没有指定则表示本机。
- port – 远程rmi的端口,如果没有指定则默认为1099。
- Servername – 注册到RMI注册中心中的jstatd的名称。
jcmd
作用
打印java进程涉及的基本类,线程和VM信息。
jhat
作用
读取内存堆转储,然后可以通过http://ip:7000来查看结果。
示例
假设已经使用jmap工具将堆文件保存为了MyDump.prof
- 执行:jhat MyDump.prof
- 访问:http://ip:7000
常用操作
Show instance counts for all classes (excluding platform),平台外的所有对象信息
Show heap histogram 以树状图形式展示堆情况
选项
-J<flag>
因为 jhat 命令实际上会启动一个JVM来执行, 通过 -J 可以在启动JVM时传入一些启动参数. 例如, -J-Xmx512m 则指定运行 jhat 的Java虚拟机使用的最大堆内存为 512 MB。如果需要使用多个JVM启动参数,则传入多个 -Jxxxxxx.
-stack false|true
关闭对象分配调用栈跟踪(tracking object allocation call stack)。 如果分配位置信息在堆转储中不可用. 则必须将此标志设置为 false. 默认值为 true.
-refs false|true
关闭对象引用跟踪(tracking of references to objects)。 默认值为 true. 默认情况下, 返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references), 会统计/计算堆中的所有对象。
-port port-number
设置 jhat HTTP server 的端口号. 默认值 7000.
-exclude exclude-file
指定对象查询时需要排除的数据成员列表文件(a file that lists data members that should be excluded from the reachable objects query)。 例如, 如果文件列列出了 java.lang.String.value , 那么当从某个特定对象 Object o 计算可达的对象列表时, 引用路径涉及 java.lang.String.value 的都会被排除。
-baseline exclude-file
指定一个基准堆转储(baseline heap dump)。 在两个 heap dumps 中有相同 object ID 的对象会被标记为不是新的(marked as not being new). 其他对象被标记为新的(new). 在比较两个不同的堆转储时很有用.
-debug int
设置 debug 级别. 0 表示不输出调试信息。 值越大则表示输出更详细的 debug 信息.
-version
启动后只显示版本信息就退出
-h
显示帮助信息并退出. 同 -help
-help
显示帮助信息并退出. 同 -h
jinfo
作用
查看/调整 虚拟机的参数。
虚拟机参数可通过此命令查看:
Linux环境:java -XX:+PrintFlagsInitial | grep manageable
Window环境:java -XX:+PrintFlagsInitial | findstr manageable
格式:
jinfo [option] pid (to connect to running process)
jinfo [option] <executable <core> (to connect to a core file)
jinfo [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server)
示例
命令 | 作用 |
jinfo -flags 2788 | 查看进程号为2788的所有jvm参数 |
jinfo -sysprops2788 | 查看进程号为2788的所有java系统参数 |
jinfo -flag MinHeapFreeRatio 2788 | 查看进程号为2788的MinHeapFreeRatio 的值 |
jinfo -flag -PrintGC 27250 jinfo -flag -PrintGCDetails 27250 | 关闭GC日志功能 |
jinfo -flag +PrintGC 27250 jinfo -flag +PrintGCDetails 27250 | 打开GC日志功能 |
选项
选项 | 含义 |
-flag <name> | to print the value of the named VM flag |
-flag [+|-]<name> | to enable or disable the named VM flag |
-flag <name>=<value> | to set the named VM flag to the given value |
-flags | to print VM flags |
-sysprops | to print Java system properties |
<no option> | to print both of the above |
-h | -help | to print this help message |
jmap
作用
打印某个Java进程的内存中的对象、堆信息(以二进制形式)。
生成的dump文件可通过工具进行分析,从而可以排查出OOM、内存泄露等原因。
可分析jmap生成的dump文件的工具:
- MAT(内存分析工具(Memory Analysis Tool))
- jprofiler
- VisualVM
- jhat
其他生成dump的文件的方法
除了jmap这种方式还有如下方法生成dump文件:
- 启动应用时加参数:-XX:HeapDumpOnOutOfMemoryError。
- 这样在虚拟机发生OOM的时候自动生成堆的dump文件
- kill -3 xxx
- kill -3 xxx命令发出进程退出信号”吓唬”一下虚拟机,也能拿到dump文件。
格式
jmap [option] <pid> (to connect to running process)
jmap [option] <executable <core> (to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server)
示例
命令 | 作用 |
jmap -heap <pid> | 打印堆信息(Heap Configuration、Eden Space、From Space、To Space、PS Old Generation、internal string) |
jmap -dump:live,format=b,file=heap.bin <pid> | 把pid的堆信息写到heap.bin里。 |
jmap -histo <pid> | 打印pid的直方图。 可查看当前Java进程创建的活跃对象数目和占用内存大小。 |
选项
选项 | 含义 |
-dump[:live,]format=b,file=<filename> | 使用hprof二进制形式,输出jvm的heap内容到文件。 :live:可选,若指定,则会先触发Full GC,然后再dump数据。 |
-finalizerinfo | 打印正等候回收的对象的信息。 |
-heap | 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况。 |
-histo[:live] | 打印直方图:每个class的实例数目,内存占用,类全名信息.。VM的内部类名字开头会加上前缀”*”。 :live:可选,若指定,则会先触发Full GC,然后再dump数据。 |
-F | 强制。在pid没有响应的时候,使用-dump或者-histo来强制生成堆信息或者直方图。 在这个模式下,live子参数无效。 |
-h | -help | 打印辅助信息 |
-J | 给jmap启动的jvm传递参数。 |
jstack
作用
打印java堆栈信息。可以用来定位线程间死锁、锁等待、等待外部资源等。
格式:
jstack [-l] <pid> (to connect to running process)
jstack -F [-m] [-l] <pid> (to connect to a hung process)
jstack [-m] [-l] <executable> <core> (to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname> (to connect to a remote debug server)
注意:64位需指定选项”-J-d64″,Windows的jstack只支持这种方式:jstack [-l] pid
示例
命令 | 作用 |
jstack pid | 打印pid的堆栈信息 |
选项
选项 | 含义 |
-F | “jstack [-l] pid”没有响应的时候强制打印栈信息 |
-l | 长列表。打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表 |
-m | 打印java和native c/c++框架的所有栈信息。 |
-h | -help | 打印帮助信息 |
pid | java进程id,可以用jps查询 |
结果含义
线程状态(java.lang.Thread.State)
符号 | 含义 |
NEW | 未启动的线程的状态 |
RUNNABLE | 表示线程具备所有运行条件:在运行队列中准备操作系统的调度,或者正在运行。 |
BLOCKED | 受阻塞并且正在等待监视器锁的某一线程的线程状态。 |
WAITING | 某一等待线程的线程状态。某一线程因为调用下列方法之一而处于等待状态: 不带超时值的 Object.wait 不带超时值的 Thread.join |
TIMED_WAITING | 具有指定等待时间的某一等待线程的线程状态。某一线程因为调用以下带有指定正等待时间的方法之一而处于定时等待状态: Thread.sleep 带有超时值的 Object.wait 带有超时值的 Thread.join |
TERMINATED | 已终止线程的线程状态。线程已经结束执行。 |
其他结果
结果 | 含义 |
waiting on condition | 该状态出现在线程等待某个条件的发生,比如等待IO、等待网络、等待sleep时间结束、wait时间结束等,具体等待的原因可以结合stack查看。 |
waiting for monitor entry | Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class对象的锁。每一个对象都有,也仅有一个 monitor。每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在 “Wait Set”中等待的线程状态是 “in Object.wait()”。 |
先看 “Entry Set”里面的线程。我们称被 synchronized保护起来的代码段为临界区。当一个线程申请进入临界区时,它就进入了 “Entry Set”队列。对应的 code就像:
synchronized(obj) {
………
}
这时有两种可能性:
- 该 monitor不被其它线程拥有, Entry Set里面也没有其它等待线程。
- 本线程即成为相应类或者对象的 Monitor的 Owner,执行临界区的代码
- 该 monitor被其它线程拥有
- 本线程在 Entry Set队列中等待。
在第一种情况下,线程将处于 “Runnable”的状态,而第二种情况下,线程 DUMP会显示处于 “waiting for monitor entry”。
in Object.wait() :当线程获得了 Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(一般就是被 synchronized 的对象)的 wait() 方法,放弃了 Monitor,进入 “Wait Set”队列。只有当别的线程在该对象上调用了 notify() 或者 notifyAll() , “ Wait Set”队列中线程才得到机会去竞争,但是只有一个线程获得对象的 Monitor,恢复到运行态。在 “Wait Set”中的线程, DUMP中表现为: in Object.wait()
jstack分析死锁的例子
public class DeadLockTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread, "thread-1");
Thread thread2 = new Thread(myThread, "thread-2");
thread1.start();
thread2.start();
}
private static class MyThread implements Runnable {
private Object object1 = new Object();
private Object object2 = new Object();
public void methodA() {
synchronized (object1) {
synchronized (object2) {
System.out.println("Thread:" + Thread.currentThread().getName() + "invoke methodA");
}
}
}
public void methodB() {
synchronized (object2) {
synchronized (object1) {
System.out.println("Thread:" + Thread.currentThread().getName() + "invoke methodB");
}
}
}
@Override
public void run() {
for(int i = 0; i < 1000; i++) {
methodA();
methodB();
}
}
}
}
卡住时,jstack -l pid后可直接看到jstack直接输出了死锁信息,从thread1和thread2的线程栈也可以看出出现互相等待。
请先
!