命令行工具
jps
(JVM Process Status Tool),类似于Linux的ps命令,用于列举正在运行的虚拟机进程,并显示虚拟机执行主类(main函数所在的类)名称以及这些进程的本地虚拟机唯一ID(LVMID local virtual machine Identifier)。
jps [-q] [-mlvV] [<hostid>]
-q:只输出LVMID,省略主类的名称。
-m:输出虚拟机进程启动时传递给主类main函数的参数
-l:输出主类的全名,如果进程执行的是jar包,输出jar路径。
-v:输出虚拟进程启动时JVM参数。
jps -q
8424
5180
8268
jstat
(JVM Statics-Monitoring Tool) 是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中远程虚拟机进程中的类加载、内存、垃圾收集、JIT编译等运行数据。
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
vmid :如果是本地虚拟机进程,VMID和LVMID是一致的。
interval:表示查询间隔。
count:表示查询次数。
如果省略interval,count两个参数,表示只查询一次。
option具体现象和作用如下:
-class:监视类装载、卸载数量、总空间以及类装载所耗费的时间。
-compiler:输出JIT编译器编译过的方法、耗时等信息。
-gc:监视java堆状况,包括Eden区,survivor区,老年代,永久代等的容量,已用空间、GC时间合计等信息。
-gccapacity:监视内容和-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间。
-gccause:与gcutil功能一样,但是会额外输出导致上一次GC产生的原因。
-gcmetacapacity:显示有关元空间大小的统计信息。
-gcnew:监视新生代GC状况。
-gcnewcapacity:监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间。
-gcold:监视老年代的GC状况。
-gcoldcapacity:监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间。
-gcutil:监视内容和-gc基本相同,但输出主要已使用空间占总空间的百分比。
-printcompilation:输出已经被JIT编译的方法。
jstat -gc 5180 1000 10
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
5120.0 5120.0 3825.2 0.0 33280.0 25547.9 87552.0 8.0 17536.0 17143.3 2176.0 2005.4 2 0.017 0 0.000 0.017
S0C:当前survivor space 0总容量(kB)
S1C:当前survivor space 1总容量(kB)
S0U:survivor space 0已使用容量(kB)
S1U:survivor space 1已使用容量(kB)
EC:当前eden space总容量(kB)
EU:eden space已使用容量(kB)
OC:当前old space总容量(kB)
OU:old space的已使用容量(kB)
MC:Metaspace 总容量(kB)
MU:Metacspace已使用容量(kB)
CCSC:压缩类空间总容量(kB)
CCSU:已使用的压缩类空间容量(kB)
YGC:Young generation GC次数
YGCT:Young generation GC总耗时
FGC:Full GC次数
FGCT:Full GC总耗时
GCT:GC总耗时
jinfo
(Configuration Info for Java) 实时地查看和调整虚拟机的各项参数。
格式
jinfo [ option ] pid
jinfo [ option ] executable core
jinfo [ option ] [server-id@]remote-hostname-or-IP
参数说明
pid 对应jvm的进程id
executable core 产生core dump文件
[server-id@]remote-hostname-or-IP 远程的ip或者hostname,server-id标记服务的唯一性id
option
no option 输出全部的参数和系统属性
-flag name 输出对应名称的参数
-flag [+|-]name 开启或者关闭对应名称的参数
-flag name=value 设定对应名称的参数
-flags 输出全部的参数
-sysprops 输出系统属性
jinfo 5180
Attaching to process ID 5180, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
Java System Properties:
java.vendor = Oracle Corporation
preload.project.path = E:/Java/jvm
sun.java.launcher = SUN_STANDARD
...
jinfo -flags 5180
Attaching to process ID 5180, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=734003200 -XX:MaxNewSize=244318208 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:
+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=E:/Java/jvm -Dpreload.config.path=C:/Users/chuang.ji/.IntelliJIdea20
18.3/config/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djava.net.preferIPv4Stack=true -Dio.netty.initialSeedUniquifier=-2925694128290007609 -Dfile.encoding=GBK -Duser.langua
...
jmap
(Memory Map for Java) 命令用于生成堆转储快照(一般称为heapdump或dump文件)。另外它还可以查下finalize执行队列、Java堆和永久代的详细情况。不过jmap有一些功能在Windows平台受限。
命令格式:
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)
option可以是如下选项:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
jstack
(Stack Trace for Java) 该命令用于生产虚拟机当前时刻的线程快照(threaddump)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情,或者等待着什么资源。
命令格式:
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)
option选项:
-F 当正常输出的请求不被响应时,强制输出线程堆栈。
-l 除堆栈外,显示锁的附加信息。
-m 打印java和native c/c++框架的所有栈信息
可视化工具
jconsole
(ava Monitoring and Management Console是一种基于JMX的可视化监视、管理工具。
启动JConsole
通过JDK/bin目录下的jconsole.exe启动JConsole后,将会自动搜索本机运行的所有虚拟机进程,双击选择其中一个进程即可开机监控,也可以使用下面的“远程进程”功能来连接远程服务器,对远程虚拟机进行监控。
进入JConsole主界面后可以看到主界面包括“概览”,“内存”,“线程”,“类”,“VM概要”,“MBean”。
“概览”页签显示的是整个虚拟机注意运行数据的概览,其中包括“堆内存使用情况”、“线程”、“类”、“CPU事情情况”4种信息的曲线图。这些曲线图是后面“内存”、“线程”,“类”页签的信息汇总。
内存监控
“内存”页签相对于可视化的jstat命令,用于监视受收集器管理的虚拟机内存(Java堆和永久代)的变化趋势。
运行下面的程序,同时利用JConsole进行监控:
import java.util.ArrayList;
import java.util.List;
public class jconsoledemo1 {
static class OOMObject{
public byte[] placeholder = new byte[64*1024];
}
public static void fillHeap(int num) throws InterruptedException{
Thread.sleep(10000);
List<OOMObject> list = new ArrayList<OOMObject>();
for(int i = 0; i < num; i++){
Thread.sleep(50);
list.add(new OOMObject());
}
System.gc();
}
public static void main(String[] args) throws Exception{
fillHeap(1000);
}
}
JVM的配置:-Xms100m -Xmx100m -XX:+UseSerialGC -XX:+PrintGCDetails
GC日志
[GC (Allocation Failure) [DefNew: 27328K->3392K(30720K), 0.0264937 secs] 27328K->11669K(99008K), 0.0268020 secs] [Times: user=0.02 sys=0.00, real=0.03 secs]
[GC (Allocation Failure) [DefNew: 30693K->3373K(30720K), 0.0381057 secs] 38970K->36132K(99008K), 0.0381500 secs] [Times: user=0.00 sys=0.03, real=0.04 secs]
[GC (Allocation Failure) [DefNew: 30645K->3365K(30720K), 0.0270089 secs] 63404K->61645K(99008K), 0.0270596 secs] [Times: user=0.03 sys=0.00, real=0.03 secs]
[Full GC (System.gc()) [Tenured: 58279K->66334K(68288K), 0.0267295 secs] 67333K->66334K(99008K), [Metaspace: 9583K->9583K(1058816K)], 0.0267930 secs] [Times: user=0.02 sys=0.00, real=0.03 secs]
Heap
def new generation total 30720K, used 476K [0x00000000f9c00000, 0x00000000fbd50000, 0x00000000fbd50000)
eden space 27328K, 1% used [0x00000000f9c00000, 0x00000000f9c77328, 0x00000000fb6b0000)
from space 3392K, 0% used [0x00000000fba00000, 0x00000000fba00000, 0x00000000fbd50000)
to space 3392K, 0% used [0x00000000fb6b0000, 0x00000000fb6b0000, 0x00000000fba00000)
tenured generation total 68288K, used 66334K [0x00000000fbd50000, 0x0000000100000000, 0x0000000100000000)
the space 68288K, 97% used [0x00000000fbd50000, 0x00000000ffe17958, 0x00000000ffe17a00, 0x0000000100000000)
Metaspace used 9589K, capacity 9954K, committed 10240K, reserved 1058816K
class space used 1131K, capacity 1242K, committed 1280K, reserved 1048576K
线程监控
“线程”页签的功能相对于可视化的jstack命令,遇到线程停顿时可以使用这个页签进行监控分析。线程长时间停顿的主要原因有:等待外部资源(数据库连接,网络资源,设备资源等),死循环,锁等待(活锁和死锁)
/**
* 线程死锁等待演示
*/
public class jconsoledemo3 {
static class SynAddRunable implements Runnable{
int a, b;
public SynAddRunable(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++){
new Thread(new SynAddRunable(1,2)).start();
new Thread(new SynAddRunable(2,1)).start();
}
}
}
这段代码开了200个线程去计算1+2和2+1的值,可能会导致死锁。造成死锁的原因是Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑,[-128,127]之间的数字会被缓存,当valueOf()方法传入参数在这个范围之内,将之间返回缓存中的对象。也就是说,代码中调用了200次Integer.valueOf()方法,一共返回了两个不同的对象。假如在某个线程的两个synchronized块之间发生了一次线程切换,那就会出现线程A等着被线程B持有的Integer.valueOf(1),线程B又等着被线程A持有的Integer.valueOf(2),结果出现大家都跑不下去的情况。
线程-121等待一共被线程-192持有的Integer对象,而线程-192也等待一个被线程-121持有的Integer对象。这样两个线程就互相卡住,都不存在等待锁释放的希望。
VisualVM
VisualVM(All-in-One Jave Troubleshooting Tool)是随JDK发布的功能强大的运行监视和故障处理程序。它除了运行监视、故障处理外,还提供了许多其他方面的功能,如性能分析。和JProfiler,YourKit等专业Profiling工具相比,VisualVM还有一个很大的优点:不需要被监视的程序基于特殊agent运行,因此它对应用程序的实际性能影响很小,使得它可以直接应用在生产环境中。
VisualVm可以做到如下:
显示虚拟机进程以及进程的配置、环境信息。
监视应用程序的 CPU、GC、堆、方法区以及线程的信息。
dump以及分析堆转储快照。
方法级的程序运行性能分析,找出被调用最多,运行时间最长的方法。
离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送给开发者进行Bug反馈。
启动VisualVM ,在目标应用程序中右击,选择"堆dump"或"线程dump",生成dump文件后,可以保存此文件。