一.Jps
1、概述
jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情况。
jps存放在JAVA_HOME/bin/jps,使用时为了方便请将JAVA_HOME/bin/加入到Path。
jps 命令类似与 linux 的 ps 命令,但是它只列出系统中所有的 Java 应用程序。 通过 jps 命令可以方便地查看 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息。
如果在 linux 中想查看 java 的进程,一般我们都需要 ps -ef | grep java 来获取进程 ID。
如果只想获取 Java 程序的进程,可以直接使用 jps 命令来直接查看。
2、原理
java程序在启动以后,会在java.io.tmpdir指定的目录下,就是临时文件夹里,生成一个类似于hsperfdata_User的文件夹,
这个文件夹里(在Linux中为/tmp/hsperfdata_{userName}/),有几个文件,名字就是java进程的pid,因此列出当前运行的java进程,只是把这个目录里的文件名列一下而已。
至于系统的参数什么,就可以解析这几个文件获得。
window系统显示如下:
3、基本用法
(1)参数说明
-q:只输出进程 ID
-m:输出传入 main 方法的参数
-l:输出完全的包名,应用主类名,jar的完全路径名
-v:输出jvm参数
-V:输出通过flag文件传递到JVM中的参数
[hostid]:远程服务器地址,jps 支持远程调用 [protocol:][[//]hostname][:port][/servername]
示例一:jps
无参数:显示进程的ID 和 类的名称
jps 不带参数,默认显示 进程ID 和 启动类的名称。
示例二:jps -q
参数 -q 只输出进程ID,而不显示出类的名称
示例三:jps -m
参数 -m 可以输出传递给 Java 进程(main 方法)的参数。
示例五:jps -v
参数 -v 可以显示传递给 Java 虚拟机的参数。
4、获取远程服务器 jps 信息
jps 支持查看远程服务上的 jvm 进程信息。如果需要查看其他机器上的 jvm 进程,需要在待查看机器上启动 jstatd 服务。
开启 jstatd 服务
启动 jstatd 服务,需要有足够的权限。 需要使用 Java 的安全策略分配相应的权限。
创建 jstatd.all.policy 策略文件。
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
启动 jstatd 服务器:
jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.31.241
-J 参数是一个公共的参数,如 jps、 jstat 等命令都可以接收这个参数。 由于 jps、 jstat 命令本身也是 Java 应用程序, -J 参数可以为 jps 等命令本身设置 Java 虚拟机参数。
-Djava.security.policy:指定策略文件
-Djava.rmi.server.hostname:指定服务器的ip地址(可忽略)
默认情况下, jstatd 开启在 1099 端口上开启 RMI 服务器。
二.Jinfo
1、概述
jinfo(Java Configuration Info)是 JDK 自带的命令,可以用来查看正在运行的 java 应用程序的扩展参数,包括Java System属性和JVM命令行参数;
也可以动态的修改正在运行的 JVM 一些参数。当系统崩溃时,jinfo可以从core文件里面知道崩溃的Java应用程序的配置信息。
2、Javacore 概述
Javacore,也可以称为“threaddump”或是“javadump”,它是 Java 提供的一种诊断特性,能够提供一份可读的当前运行的 JVM 中线程使用情况的快照。
即在某个特定时刻,JVM 中有哪些线程在运行,每个线程执行到哪一个类,哪一个方法。
应用程序如果出现不可恢复的错误或是内存泄露,就会自动触发 Javacore 的生成。
3、基本用法
示例一: no option
命令:jinfo pid
描述:输出当前 jvm 进程的全部参数和系统属性
示例二: -flag name
命令:jinfo -flag name pid
描述:输出对应名称的参数
使用该命令,可以查看指定的 jvm 参数的值。如:查看当前 jvm 进程是否开启打印 GC 日志。
示例三:-flag [+|-]name
命令:jinfo -flag [+|-]name pid
描述:开启或者关闭对应名称的参数
使用 jinfo 可以在不重启虚拟机的情况下,可以动态的修改 jvm 的参数。尤其在线上的环境特别有用。
使用如下:

示例四:-flag name=value
命令:jinfo -flag name=value pid
描述:修改指定参数的值。
同示例三,但示例三主要是针对 boolean 值的参数设置的。
如果是设置 value值,则需要使用 name=value 的形式。
使用如下:

jinfo虽然可以在java程序运行时动态地修改虚拟机参数,但并不是所有的参数都支持动态修改
示例五: -flags
命令:jinfo -flags pid
描述:输出全部的参数
示例六:-sysprops
命令:jinfo -sysprops pid
描述:输出当前 jvm 进行的全部的系统属性
三.Jmap
1、概述
jmap命令是一个可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。
打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。
可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,检查系统中什么对象最多,各种对象所占内存的大小等等。
当服务发生GC问题时,一般会使用jmap工具进行分析。
作用:
(1)查看堆各个对象的数量,大小;
(2)dump堆里的对象信息,然后可以用MAT分析;
(3)查看堆的配置情况和GC算法;
(4)查看堆永久代信息;
2、基本用法
示例一:no option
命令:jmap pid
描述:查看进程的内存映像信息,类似 Solaris pmap 命令。
使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。这与Solaris的pmap工具比较相似。
示例二:heap
命令:jmap -heap pid
描述:显示Java堆详细信息
打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息:
C:Usersjjs>jmap -heap 5932 Attaching to process ID 5932, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.91-b15 using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 1073741824 (1024.0MB) NewSize = 42991616 (41.0MB) MaxNewSize = 357564416 (341.0MB) OldSize = 87031808 (83.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 60293120 (57.5MB) used = 44166744 (42.120689392089844MB) free = 16126376 (15.379310607910156MB) 73.25337285580842% used From Space: capacity = 5242880 (5.0MB) used = 0 (0.0MB) free = 5242880 (5.0MB) 0.0% used To Space: capacity = 14680064 (14.0MB) used = 0 (0.0MB) free = 14680064 (14.0MB) 0.0% used PS Old Generation capacity = 120061952 (114.5MB) used = 19805592 (18.888084411621094MB) free = 100256360 (95.6119155883789MB) 16.496143590935453% used 20342 interned Strings occupying 1863208 bytes.
示例三:histo[:live]
命令:jmap -histo:live pid
描述:显示堆中对象的统计信息
其中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。打印的虚拟机内部的类名称将会带有一个’*’前缀。如果指定了live子选项,则只计算活动的对象。
示例四:clstats
命令:jmap -clstats pid
描述:打印类加载器信息
-clstats是-permstat的替代方案,在JDK8之前,-permstat用来打印类加载器的数据
打印Java堆内存的永久保存区域的类加载器的智能统计信息。对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印。
此外,包含的字符串数量和大小也会被打印。
示例五:finalizerinfo
命令:jmap -finalizerinfo pid
描述:打印等待终结的对象信息。
Number of objects pending for finalization: 0 说明当前F-QUEUE队列中并没有等待Fializer线程执行final
示例六:dump:<dump-options>
命令:jmap -dump:format=b,file=heapdump.phrof pid
描述:生成堆转储快照dump文件。
以hprof二进制格式转储Java堆到指定filename的文件中。live子选项是可选的。如果指定了live子选项,堆中只有活动的对象会被转储。
想要浏览heap dump,你可以使用jhat(Java堆分析工具)读取生成的文件。
这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用, 线上系统慎用。
生成Heap Dump文件的方法:
JMAP(Java Memory Map)
方法一:让运行中的JVM生成Dump文件
/usr/java/jdk/bin/jmap -F -dump:format=b,file=/path/to/heap/dump/heap.bin PID
方法二:让JVM在遇到OOM(OutOfMemoryError)时生成Dump文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heap/dump
用MAT分析Dump文件
MAT(Memory Analyzer)
http://www.eclipse.org/mat/
Mat是eclipse插件,要安装它.路径可到 http://www.eclipse.org/mat/downloads.php 找
如:http://download.eclipse.org/mat/1.8/update-site/
安装完插件后,eclipse的file菜单有个 Open Heap Dump
最后能生成一个很直观的图
见图:

四.Jstack
1、概述
jstack能得到运行java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。
jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64"。
Windows的jstack使用方式只支持以下的这种方式:jstack [-l] pid
如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
需要注意的问题:
(1)不同的 JAVA虚机的线程 DUMP的创建方法和文件格式是不一样的,不同的 JVM版本, dump信息也有差别。
(2)在实际运行中,往往一次 dump的信息,还不足以确认问题。建议产生三次 dump信息,如果每次 dump都指向同一个问题,才确定问题的典型性。
jstack是java虚拟机自带的一种堆栈跟踪工具。
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,
如线程间死锁、死循环、请求外部资源导致的长时间等待等。
线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
2、例子——检测死锁
示例代码
public class DeadLock implements Runnable { private int flag; private static final Object a = new Object(); private static final Object b = new Object(); public DeadLock(int flag) { this.flag = flag; } @Override public void run() { if (flag == 1) { synchronized (a) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程:"+Thread.currentThread().getName()+"尝试获取b"); synchronized (b) { System.out.println("当前线程:"+Thread.currentThread().getName()+"获得了b"); } } } else { synchronized (b) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程:"+Thread.currentThread().getName()+"尝试获取a"); synchronized (a) { System.out.println("当前线程:"+Thread.currentThread().getName()+"等待获得a"); } } } } }
public class DeadLockLauncher { public static void main(String[] args) { final DeadLock deadLock1 = new DeadLock(1); final DeadLock deadLock2 = new DeadLock(0); Thread t1 = new Thread(deadLock1, "线程1"); Thread t2 = new Thread(deadLock2, "线程2"); t1.start(); t2.start(); } }
打开命令行窗口,输入 jps
C:Usersheyfan.xie>jps 16592 Jps 17232 DeadLockLauncher 7872 17092 Launcher 14040 Launcher
死锁启动类ID为 17232, 输入 jstack -F 17232
C:Usersheyfan.xie>jstack -F 17232 Attaching to process ID 17232, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.92-b14 Deadlock Detection: Found one Java-level deadlock: ============================= "线程2": waiting to lock Monitor@0x000000001f1e0288 (Object@0x000000076ba3f420, a java/lang/Object), which is held by "线程1" "线程1": waiting to lock Monitor@0x000000001f1e1728 (Object@0x000000076ba3f430, a java/lang/Object), which is held by "线程2" Found a total of 1 deadlock. Thread 3: (state = BLOCKED) Thread 22: (state = BLOCKED) - cn.cici.frigate.logistics.dead.DeadLock.run() @bci=120, line=41 (Interpreted frame) - java.lang.Thread.run() @bci=11, line=745 (Interpreted frame) Thread 21: (state = BLOCKED) - cn.cici.frigate.logistics.dead.DeadLock.run() @bci=34, line=30 (Interpreted frame) - java.lang.Thread.run() @bci=11, line=745 (Interpreted frame) Thread 15: (state = IN_NATIVE) - java.net.SocketInputStream.socketRead0(java.io.FileDescriptor, byte[], int, int, int) @bci=0 (Interpreted frame) - java.net.SocketInputStream.socketRead(java.io.FileDescriptor, byte[], int, int, int) @bci=8, line=116 (Interpreted frame) // 省略更多的信息
可以看到* Found a total of 1 deadlock* 竞争锁定的对象为 java/lang/Object
3、例子——检测cpu高
步骤一:查看cpu占用高进程
top Mem: 16333644k total, 9472968k used, 6860676k free, 165616k buffers Swap: 0k total, 0k used, 0k free, 6665292k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 17850 root 20 0 7588m 112m 11m S 100.7 0.7 47:53.80 java 1552 root 20 0 121m 13m 8524 S 0.7 0.1 14:37.75 AliYunDun 3581 root 20 0 9750m 2.0g 13m S 0.7 12.9 298:30.20 java 1 root 20 0 19360 1612 1308 S 0.0 0.0 0:00.81 init 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root RT 0 0 0 0 S 0.0 0.0 0:00.14 migration/0
步骤二:查看cpu占用高线程
top -H -p 17850 top - 17:43:15 up 5 days, 7:31, 1 user, load average: 0.99, 0.97, 0.91 Tasks: 32 total, 1 running, 31 sleeping, 0 stopped, 0 zombie Cpu(s): 3.7%us, 8.9%sy, 0.0%ni, 87.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 16333644k total, 9592504k used, 6741140k free, 165700k buffers Swap: 0k total, 0k used, 0k free, 6781620k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 17880 root 20 0 7588m 112m 11m R 99.9 0.7 50:47.43 java 17856 root 20 0 7588m 112m 11m S 0.3 0.7 0:02.08 java 17850 root 20 0 7588m 112m 11m S 0.0 0.7 0:00.00 java 17851 root 20 0 7588m 112m 11m S 0.0 0.7 0:00.23 java 17852 root 20 0 7588m 112m 11m S 0.0 0.7 0:02.09 java 17853 root 20 0 7588m 112m 11m S 0.0 0.7 0:02.12 java 17854 root 20 0 7588m 112m 11m S 0.0 0.7 0:02.07 java
步骤三:转换线程ID
printf "%x
" 17880
45d8
步骤四:定位cpu占用线程
jstack 17850|grep 45d8 -A 30 "pool-1-thread-11" #20 prio=5 os_prio=0 tid=0x00007fc860352800 nid=0x45d8 runnable [0x00007fc8417d2000] java.lang.Thread.State: RUNNABLE at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:326) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) - locked <0x00000006c6c2e708> (a java.io.BufferedOutputStream) at java.io.PrintStream.write(PrintStream.java:482) - locked <0x00000006c6c10178> (a java.io.PrintStream) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291) at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104) - locked <0x00000006c6c26620> (a java.io.OutputStreamWriter) at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185) at java.io.PrintStream.write(PrintStream.java:527) - eliminated <0x00000006c6c10178> (a java.io.PrintStream) at java.io.PrintStream.print(PrintStream.java:597) at java.io.PrintStream.println(PrintStream.java:736) - locked <0x00000006c6c10178> (a java.io.PrintStream) at com.demo.guava.HardTask.call(HardTask.java:18) at com.demo.guava.HardTask.call(HardTask.java:9) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) "pool-1-thread-10" #19 prio=5 os_prio=0 tid=0x00007fc860345000 nid=0x45d7 waiting on condition [0x00007fc8418d3000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000006c6c14178> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
五.总结
遇到线上问题不要慌,首先确认排查问题的思路:
(1)查看日志;
(2)查看CPU情况;
(3)查看TCP情况;
(4)查看java线程,jstack;
(5)查看java堆,jmap;
(6)通过MAT分析堆文件,寻找无法被回收的对象。