一、jps
jps由jdk1.5提供,用于查看当前用户下的java进程的pid及基本信息
1、jps -help
jps的帮助命令,可用jps -h
代替:
2、jps -m
查看进程pid及main方法参数:
图中 5940 是我的eclipse进程;18648是jps进程,他的main方法参数就是-m
;27800是我启动的hbuilder软件;47852是我运行的测试函数,参数是zdg
和HK
3、jps -q
仅显示pid:
4 、jps -v
查看pid及JVM参数:
5、 jps -l
查看pid及程序所在包名:
图中29852就是我运行的测试Java程序。
二、jstack
使用jstack可查看指定进程(pid)的堆栈信息,用以分析线程情况:
NEW:未启动的。不会出现在Dump中。
RUNNABLE:在虚拟机内执行的。
BLOCKED:受阻塞并等待监视器锁。
WATING:无限期等待另一个线程执行特定操作。
TIMED_WATING:有时限的等待另一个线程的特定操作。
TERMINATED:已退出的。
1、jstack -h
帮助命令:
2、jstack [-l][-m][-F] pid
-l
:长列表,打印锁的附加信息;
-m
:打印java和native c/c++框架的所有栈信息;
-F
:没有响应的时候强制打印栈信息;
3、例
首先通过jps查看进程pid:
然后通过jstack 55872 打印堆栈信息:
图中仅是一部分信息截图,可以看到当前主线程状态是TIMED_WATING
,在程序第6行:
4、线程死锁查看:
程序:
public class JpsTest {
public static void main(String[] args) throws InterruptedException {
//创建资源
final Object a = new Object();
final Object b = new Object();
//启动线程
new Thread(new Runnable() {
@Override
public void run() {
//获取a的锁
synchronized (a) {
try {
System.out.println("i'm t1");
//等待一会儿,确保下一个线程获得另一个资源对象锁
Thread.sleep(100);
//获取b的锁
synchronized (b) {
System.out.println("t1------");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//启动线程
new Thread(new Runnable() {
@Override
public void run() {
//获取b的锁
synchronized (b) {
try {
System.out.println("i'm t2");
//等待一会儿,确保下一个线程获得另一个资源对象锁
Thread.sleep(100);
//获取a的锁
synchronized (a) {
System.out.println("t2------");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
程序中两个线程分别持有对方所需资源的锁并等待对方释放导致死锁。
查看jstack打印信息:
可以看到图中第一行显示发现了线程死锁,Thread-1等待资源 - waiting to lock <0x00000000eb4c0bf8> (a java.lang.Object),且锁住了资源 - locked <0x00000000eb4c0c08> (a java.lang.Object),Thread2则与之相反。
3、jmap与jhat
查看堆内存使用情况:
jmap -heap pid:通过可查看堆内存的配置情况及使用情况
jmap -histo pid:统计对象的创建数量
jmap -dump:format=b,file=heapDump pid:生成dump文件与jhat配合使用
jhat -port xxxx heapDump:浏览器访问localhost:xxxx即可查看dump
例:
程序(程序简陋,忽略细节):
public class JmapTest {
public static void main(String[] args) throws InterruptedException {
JmapTest test = new JmapTest(300);
fun(test);
System.out.println(test.a);
}
private JmapTest next;
private Integer a;
public JmapTest(int a) {
this.a = a;
}
//通过向一个链表递归添加对象
public static void fun(JmapTest m) throws InterruptedException {
System.out.println(m.a);
m.next = new JmapTest(++m.a);
//避免过早发送内存溢出
Thread.sleep(1000);
fun(m.next);
}
}
首先通过使用jps -l获得pid,再通过jmap -heap pid查看堆内存配置及使用情况:
配置信息:
使用情况:
接下来通过jmap -histo pid查看对象创建数量:
图中我们得程序已经创建了401个实例对象了。
通过 jmap -dump:format=b,file=heapDump pid 生成heapDump文件:
这样文件已经创建成功,再通过jhat -port xxxx heapDump 启动一个监听程序查看文件:
程序已经启动,接下来在浏览器查看: