1 jps 列出正在运行的虚拟机进程
- 参数
- -q 只输出LVMID
- -m 输出JVM启动传递给main()参数
- -l 输出主类的全名,jar包则输出jar路径
- -v 输出虚拟机启动的JVM参数
-
- 注意点
- jps 跟系统用户权限有关
2 jstat 虚拟机统计信息监视工具
- 可参考
- jstat(JVM Statistics Monitoring Tool)监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程 [1] 虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据
2.1 命令格式
- jstat [ option vmid [interval[s|ms] [count]] ]
- [option] 参数操作
- LVMID : 本地虚拟机进程PID
- [interval] : 连续输出的时间间隔
- [count] : 连续输出的次数
2.2 option 参数
- -class 监视类加载,卸载数量,总空间以及类装载所耗费的时间
- Loaded 加载class的数量
- Bytes class字节大小
- Unloaded 未加载class的数量
- Bytes 未加载class的字节大小
- Time 加载时间
jstat -class 18284
Loaded Bytes Unloaded Bytes Time
17161 31820.1 1 0.9 21.29
- -gc 监视java对状况,包括Eden区,2个Survivor区,老年代,永久代等的容量,已用空间,垃圾收集时间合计等信息
- S0C survivor0区的总容量 单位KB
- S1C survivor1区的总容量
- S0U survivor0区已经使用的容量
- S1U survivor1区已经使用的容量
- EC Eden区的总容量
- EU Eden区已使用的容量
- OC Old区的总容量
- OU Old区已使用的容量
- MC 当前元空间大小 / 方法区空间大小
- MU 当前元空间已使用大小
- CCSC 压缩类空间大小 64位压缩指针存放地方
- CCSU 压缩类空间使用大小
- YGC 新生代垃圾回收次数
- YGCT 新生代垃圾回收时间
- FGC 老年代垃圾回收次数
- FGCT 老年代垃圾回收时间
- GCT 垃圾回收总消耗时间
>jstat -gc 18284
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
20992.0 11264.0 0.0 11199.6 380416.0 53939.6 150528.0 55459.2 92632.0 87388.8 12544.0 11626.8 17 0.429 3 0.390 0.818
- -gccapacity 监视内容与-gc基本相同,输出java堆各个区域使用到的最大,最小空间
- NGCMN 新生代占用的最小空间
- NGCMX 新生代占用的最大空间
- NGC 当前新生代容量
- OGCMN 老年代占用的最小空间
- OGCMX 老年代占用的最大空间
- OGC 当前年老代的容量
- MCMN 方法区占用的最小空间
- MCMX 方法区占用的最大空间
- CCSMN 压缩类空间最小空间
- CCSMX 压缩类空间最大空间
jstat -gccapacity 18284
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
64512.0 1030656.0 469504.0 20992.0 11264.0 380416.0 130048.0 2061824.0 150528.0 150528.0 0.0 1130496.0 92632.0 0.0 1048576.0 12544.0 17 3
- -gcutil 监视内容与-gc基本相同,输出已使用空间占总空间的百分比
- -gccause 与-gcutil功能一样,但是会额外输出导致上次垃圾收集产生的原因
- -gcnew 监视新生代垃圾收集状况
- TT Tenuring threshold(提升阈值)
- MTT 最大的tenuring threshold
- DSS 期望的幸存区大小
jstat -gcnew 18284
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
20992.0 11264.0 0.0 11199.6 3 15 24064.0 380416.0 137958.6 17 0.429
- -gcnewcapacity 与-gcnew基本相同,主要输出最大,最小空间
- -gcold 监视老年代垃圾收集情况
- -gcoldcapacity 与-gcold基本相同,输出主要关注使用到的最大,最小空间
- -gcpermcapacity jdk8 没有了 输出永久代使用到的最大,最小空间
- -compiler 输出即时编译器编译过的方法,耗时等信息
- Compiled : 编译数量
- Failed : 编译失败数量
- Invalid : 无效数量
- Time : 编译耗时
- FailedType : 失败类型
- FailedMethod : 失败方法的全限定名
jstat -compiler 18284
Compiled Failed Invalid Time FailedType FailedMethod
8965 2 0 3.64 1 com/fasterxml/classmate/ResolvedTypeWithMembers resolveMemberMethods
- -printcompilation 输出已经被即时编译的方法
3 jinfo Java配置信息工具
- jinfo(Configuration Info for Java)的作用是实时查看和调整虚拟机各项参数
3.1 命令格式
- jinfo [option] [args] LVMID
- option参数
- -flag[+|-]name 或者-flag name=value在运行期修改一部分运行期可写的虚拟机参数值
- -flag
输出指定args参数的值 - -flags : 输出所有JVM参数的值
- -sysprops : 输出系统属性,等同于System.getProperties()
- 示例
jinfo -flag MaxHeapSize 18284
-XX:MaxHeapSize=3166699520
4 jmap:Java内存映像工具
- jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)
- 不仅获取堆存储快照,
- 可以查询finalize执行队列
- java堆和方法区的详细,如空间使用率,当前用的是哪种收集器等
- 要想获取Java堆转储快照也可以 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/pi/software/dataGathering/logs
4.1 命令格式
- jmap [ option ] vmid
4.2 option参数
- -dump 生成java堆存储快照
- 格式 -dump:[live,]format=b,file=
- live参数 说明是否只dump出存活对象
- 可以MAT(Memory Anlysis Tool)打开
- 格式 -dump:[live,]format=b,file=
jmap -dump:live,format=b,file=D:\dump.hprof 1556
Dumping heap to D:\dump.hprof ...
Heap dump file created
- -finalizerinfo 显示在F-Queue中等待Finalizer线程执行finalize方法的对象
jmap -finalizerinfo 1556
Attaching to process ID 1556, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
Number of objects pending for finalization: 0
可以看到当前F-QUEUE队列中并没有等待Finalizer线程执行finalizer方法的对象
- -heap 显示java堆详细信息,如使用了哪种回收器,参数配置,分代状况等
jmap -heap 1556
Attaching to process ID 1556, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
using thread-local object allocation.
Parallel GC with 4 thread(s) # GC 方式 JVM默认组合 UseParallelGC + UseParallelOldGC组合
Heap Configuration: #堆内存初始化配置
MinHeapFreeRatio = 0 #对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
MaxHeapFreeRatio = 100 #对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
MaxHeapSize = 3166699520 (3020.0MB) #对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize = 66060288 (63.0MB) #对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
MaxNewSize = 1055391744 (1006.5MB) #对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
OldSize = 133169152 (127.0MB) #对应jvm启动参数-XX:OldSize=:设置JVM堆的‘老生代’的大小
NewRatio = 2 #对应-XX:NewRatio=:‘老生代’和‘新生代’的大小比率 老年代 2/3的内存
SurvivorRatio = 8 #对应-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
MetaspaceSize = 21807104 (20.796875MB) #对应-XX:MetaspaceSize=(初始化元空间大小)
CompressedClassSpaceSize = 1073741824 (1024.0MB) #指针压缩的大小 起作用 前提是能开启压缩指针
MaxMetaspaceSize = 17592186044415 MB #对应-XX:MaxMetaspaceSize= 元空间最大值
G1HeapRegionSize = 0 (0.0MB) #设置的 G1 区域的大小
Heap Usage: #堆内存使用情况
PS Young Generation
Eden Space: #Eden区内存分布
capacity = 441450496 (421.0MB) #Eden区总容量
used = 52597000 (50.16040802001953MB) #Eden区已使用
free = 388853496 (370.83959197998047MB) #Eden区剩余容量
11.914586228033142% used #Eden区使用比率
From Space: # 其中一个Survivor区的内存分布
capacity = 20971520 (20.0MB)
used = 0 (0.0MB)
free = 20971520 (20.0MB)
0.0% used
To Space:
capacity = 21495808 (20.5MB)
used = 0 (0.0MB)
free = 21495808 (20.5MB)
0.0% used
PS Old Generation #当前的Old区内存分布
capacity = 251658240 (240.0MB)
used = 44871056 (42.79237365722656MB)
free = 206787184 (197.20762634277344MB)
17.830155690511067% used
- -histo 显示java堆中对象统计,包括类,实例数量,合计容量
- histo[:live]
map -histo:live 12208
num instances bytes class name
7099: 1 16 sun.util.locale.InternalLocaleBuilder$CaseInsensitiveChar
7100: 1 16 sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider
7101: 1 16 sun.util.locale.provider.CalendarDataUtility$CalendarFieldValueNamesMapGetter
7102: 1 16 sun.util.locale.provider.CalendarDataUtility$CalendarWeekParameterGetter
7103: 1 16 sun.util.locale.provider.CalendarNameProviderImpl$LengthBasedComparator
7104: 1 16 sun.util.locale.provider.SPILocaleProviderAdapter
7105: 1 16 sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter
7106: 1 16 sun.util.resources.LocaleData
7107: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total 875349 42051800
- -permstat 以ClassLoader为统计口径显示永久代内存状态 jdk7
- -clstats jdk8 这个参数
jmap -clstats 12208
Attaching to process ID 12208, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader classes bytes parent_loader alive? type
2988 5231335 null live
0x0000000704407040 1 880 0x000000070340dc48 dead sun/reflect/DelegatingClassLoader@0x00000007c0009df8
...
0x00000007059b0a60 1 880 0x000000070340dc48 dead sun/reflect/DelegatingClassLoader@0x00000007c0009df8
0x00000007059c6460 1 880 0x000000070340dc48 dead sun/reflect/DelegatingClassLoader@0x00000007c0009df8
total = 322 15296 25948667 N/A alive=1, dead=321 N/A
- -F
- 强制模式 当-dump或者-histo 参数没有响应,此模式下,不支持live子选项
5 jhat 虚拟机堆转储快照分析工具
- JDK提供jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照
- 一般不会用,因为一般不会在服务器上分析堆转储快照。 一般用VisualVM,或者MAT
- 用于分析的机器一般也是服务器,由于加载dump快照文件需要比生成dump更大的内存,所以一般在64位JDK、大内存的服务器上进行。
6 jstack Java堆栈跟踪工具
- jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)
- 目的: 定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的常见原因。线程出现停顿时通过jstack来查看各个线程的调用堆栈,就可以获知没有响应的线程到底在后台做些什么事情,或者等待着什么资源
6.1 命令格式
- jstack [option] LVMID
6.2 option参数
-F 当正常输出的请求不被响应时,强制输出线程堆栈
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用到本地方法的话,可以显示c/c++的堆栈
-
例子 输出到文件
- docker exec 1439-provider-electricity-repair jstack 6 > /root/stack.log
-
死锁例子
- 注意点
- wait on monitor entry: 被阻塞的,肯定有问题
- runnable : 注意IO线程
- in Object.wait(): 注意非线程池等待
- 注意点
public class JstackTest01 {
public static Object lok2 = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (JstackTest01.class) {
System.out.println("JstackTest01 get JstackTest01 lock");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lok2) {
System.out.println("JstackTest01 get lok2 ");
}
}
},"JstackTest01").start();
new Thread(()->{
synchronized (lok2) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("JstackTest02 get lok2");
synchronized (JstackTest01.class) {
System.out.println("JstackTest02 get JstackTest01 lock ");
}
}
},"JstackTest02").start();
}
}
docker exec 1439-provider-electricity-repair jstack 6 > /root/stack.log
jstack 18736
"JstackTest02" #12 prio=5 os_prio=0 tid=0x000000001baf2800 nid=0x10e4 waiting for monitor entry [0x000000001c38f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.test.jstack.JstackTest01.lambda$main$1(JstackTest01.java:36)
- waiting to lock <0x00000007814702f8> (a java.lang.Class for com.test.jstack.JstackTest01)
- locked <0x0000000781471d80> (a java.lang.Object)
at com.test.jstack.JstackTest01$$Lambda$2/932172204.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"JstackTest01" #11 prio=5 os_prio=0 tid=0x000000001baf1800 nid=0x262c waiting for monitor entry [0x000000001c28e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.test.jstack.JstackTest01.lambda$main$0(JstackTest01.java:22)
- waiting to lock <0x0000000781471d80> (a java.lang.Object)
- locked <0x00000007814702f8> (a java.lang.Class for com.test.jstack.JstackTest01)
at com.test.jstack.JstackTest01$$Lambda$1/769287236.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
...
Found one Java-level deadlock: #指出造成死锁的两个线程的内容
=============================
"JstackTest02":
waiting to lock monitor 0x0000000019a306e8 (object 0x00000007814702f8, a java.lang.Class),
which is held by "JstackTest01"
"JstackTest01":
waiting to lock monitor 0x0000000019a2dcf8 (object 0x0000000781471d80, a java.lang.Object),
which is held by "JstackTest02"
Java stack information for the threads listed above: #显示更详细的死锁的信息
===================================================
"JstackTest02":
at com.test.jstack.JstackTest01.lambda$main$1(JstackTest01.java:36)
- waiting to lock <0x00000007814702f8> (a java.lang.Class for com.test.jstack.JstackTest01) #使用synchronized申请对象锁未成功,在JstackTest01 锁的_EntryList等待
- locked <0x0000000781471d80> (a java.lang.Object) #使用synchronized申请对象锁成功,监视器的拥有者
at com.test.jstack.JstackTest01$$Lambda$2/932172204.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"JstackTest01":
at com.test.jstack.JstackTest01.lambda$main$0(JstackTest01.java:22)
- waiting to lock <0x0000000781471d80> (a java.lang.Object)
- locked <0x00000007814702f8> (a java.lang.Class for com.test.jstack.JstackTest01)
at com.test.jstack.JstackTest01$$Lambda$1/769287236.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
- jstack信息解读
- locked 如locked <0x0000000781471d80> synchronized,获取到了锁
- waiting to lock , synchronized,等待获取锁,在对应锁Monitor 对象_EntryList属性中, 线程状态Blocked
- waiting on ,synchronized,调用了wait方法,在对应锁Monitor 对象_WaitSet属性中,线程状态WAITING或TIMED_WATING。
- parking to wait for 不是synchronized体系, 阻塞,循环cas实现的锁
public class JstackTest2 {
static Lock lock1 = new ReentrantLock();
static Lock lock2 = new ReentrantLock();
public static void main(String[] args) {
new Thread(()->{
lock1.lock();
System.out.println("JstackTest01 get lock1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock2.lock();
System.out.println("JstackTest01 get lock2");
},"JstackTest01").start();
new Thread(()->{
lock2.lock();
System.out.println("JstackTest02 get lock2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock1.lock();
System.out.println("JstackTest02 get lock1");
},"JstackTest02").start();
}
}
jstack 6708
"JstackTest02" #12 prio=5 os_prio=0 tid=0x000000001bb25800 nid=0x1e04 waiting on condition [0x000000001c43e000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007814778a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
at com.test.jstack.JstackTest2.lambda$main$1(JstackTest2.java:38)
at com.test.jstack.JstackTest2$$Lambda$2/1848402763.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"JstackTest01" #11 prio=5 os_prio=0 tid=0x000000001bb24800 nid=0x20c8 waiting on condition [0x000000001c33e000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007814778d0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
at com.test.jstack.JstackTest2.lambda$main$0(JstackTest2.java:24)
at com.test.jstack.JstackTest2$$Lambda$1/1199823423.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
...
Found one Java-level deadlock:
=============================
"JstackTest02":
waiting for ownable synchronizer 0x00000007814778a0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "JstackTest01"
"JstackTest01":
waiting for ownable synchronizer 0x00000007814778d0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "JstackTest02"
Java stack information for the threads listed above:
===================================================
"JstackTest02":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007814778a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
at com.test.jstack.JstackTest2.lambda$main$1(JstackTest2.java:38)
at com.test.jstack.JstackTest2$$Lambda$2/1848402763.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"JstackTest01":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007814778d0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
at com.test.jstack.JstackTest2.lambda$main$0(JstackTest2.java:24)
at com.test.jstack.JstackTest2$$Lambda$1/1199823423.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
- 参考
- Jstack
- 深入理解java虚拟机