所有分类
  • 所有分类
  • 未分类

Java调试–排查类工具

简介

本文介绍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

  1. 执行:jhat MyDump.prof
  2. 访问: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
-flagsto print VM flags
-syspropsto print Java system properties
<no option>to print both of the above
-h | -helpto print this help message

jmap

作用

打印某个Java进程的内存中的对象、堆信息(以二进制形式)。

生成的dump文件可通过工具进行分析,从而可以排查出OOM、内存泄露等原因。

可分析jmap生成的dump文件的工具:

  1. MAT(内存分析工具(Memory Analysis Tool))
  2. jprofiler
  3. VisualVM
  4. jhat

其他生成dump的文件的方法

        除了jmap这种方式还有如下方法生成dump文件:

  1. 启动应用时加参数:-XX:HeapDumpOnOutOfMemoryError。
  2. 这样在虚拟机发生OOM的时候自动生成堆的dump文件
  3. kill -3 xxx
  4. 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打印帮助信息
pidjava进程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 entryMonitor是 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) {

………

}

这时有两种可能性:

  1. 该 monitor不被其它线程拥有, Entry Set里面也没有其它等待线程。
  2. 本线程即成为相应类或者对象的 Monitor的 Owner,执行临界区的代码
  3. 该 monitor被其它线程拥有
  4. 本线程在 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的线程栈也可以看出出现互相等待。 ​

1

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录