1、环境
一个可运行的java程序。本例选择的是xboot (一个基于springboot 开发的后台管理框架)附上地址。jdk版本:1.8
https://github.com/Exrick/xboot
2、命令
2.1 Jinfo
先用jps 命令查看应用的进程
C:\Users\lujw0>jps
1128 XbootApplication
14924 Jps
通过jps命令可以查出xboot 项目的进程id是1128。
- 查看正在运行的Java应用程序的扩展参数
C:\Users\lujw0>jinfo -flags 1128
Attaching to process ID 1128, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.102-b14
Non-default VM flags: -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote -XX:CICompilerCount=3 -XX:InitialHeapSize=134217728 -XX:+ManagementServer -XX:MaxHeapSize=2120220672 -XX:MaxNewSize=706740224 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:TieredStopAtLevel=1 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:4099,suspend=y,server=n -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:C:\Users\lujw0\.IntelliJIdea2019.1\system\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8
上边的这些参数下面会讲,都是对jvm调优配置的一些参数。
- 查看java 系统参数
C:\Users\lujw0>jinfo -sysprops 1128
Attaching to process ID 1128, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.102-b14
spring.output.ansi.enabled = always
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.102-b14
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_102\jre\bin
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
java.rmi.server.randomIDs = true
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level =
sun.java.launcher = SUN_STANDARD
user.script =
user.country = CN
user.dir = F:\bdyhwork\wenda_bms
java.vm.specification.name = Java Virtual Machine Specification
PID = 1128
intellij.debug.agent = true
java.runtime.version = 1.8.0_102-b14
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = C:\Program Files\Java\jdk1.8.0_102\jre\lib\endorsed
line.separator =
java.io.tmpdir = C:\Users\lujw0\AppData\Local\Temp\
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = C:\Program Files\Java\jdk1.8.0_102\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files (x86)\NetSarang\Xshell 6\;C:\Program Files (x86)\NetSarang\Xftp 6\;E:\soft\node\nodeinstall\;C:\windows\system32\;C:\Program Files\TortoiseGit\bin;C:\Program Files\Git\cmd;C:\Users\lujw0\AppData\Local\Android\sdk\platform-tools;C:\Users\lujw0\AppData\Local\Microsoft\WindowsApps;E:\soft\idea 2019\IntelliJ IDEA 2019.1\plugins\maven\lib\maven3\bin;E:\soft\Git\bin;E:\soft\Git\mingw32\libexec\git-core;C:\Users\lujw0\AppData\Roaming\npm;E:\soft\webstom\WebStorm 2019.2.1\bin;C:\Program Files\Java\jdk1.8.0_102\bin;C:\Program Files\Java\jdk1.8.0_102\jre\bin;.
spring.beaninfo.ignore = true
jboss.modules.system.pkgs = com.intellij.rt
java.class.version = 52.0
java.specification.name = Java Platform API Specification
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
spring.liveBeansView.mbeanDomain =
os.version = 10.0
user.home = C:\Users\lujw0
user.timezone = Asia/Shanghai
catalina.useNaming = false
java.awt.printerjob = sun.awt.windows.WPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
catalina.home = C:\Users\lujw0\AppData\Local\Temp\tomcat.5173769956863843077.8888
user.name = bdzh01
java.class.path = C:\Users\lujw0\AppData\Local\Temp\classpath1301191800.jar;C:\Users\lujw0\.IntelliJIdea2019.1\system\captureAgent\debugger-agent.jar
com.sun.management.jmxremote =
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = cn.exrick.xboot.XbootApplication
java.home = C:\Program Files\Java\jdk1.8.0_102\jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_102
java.ext.dirs = C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
sun.boot.class.path = C:\Program Files\Java\jdk1.8.0_102\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_102\jre\classes
java.awt.headless = true
java.vendor = Oracle Corporation
catalina.base = C:\Users\lujw0\AppData\Local\Temp\tomcat.5173769956863843077.8888
spring.application.admin.enabled = true
file.separator = \
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
jinfo -sysprops 这个命令会更加详细会打印出项目运行的环境信息。
2.2 jstat
jstat:该命令可以插件堆内存各部分的使用量,以及加载类的数量。命令格式如下 jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]
- 类加载统计
C:\Users\lujw0>jstat -class 1128
Loaded Bytes Unloaded Bytes Time
16315 30104.4 0 0.0 37.11
Loaded:加载class的数量
Bytes:所占用空间大小
Unloaded:未加载数量
Bytes:未加载占用空间
Time:时间
-垃圾回收统计
C:\Users\lujw0>jstat -gc 1128
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
5632.0 28160.0 5328.0 0.0 525824.0 463666.6 138752.0 96939.8 86912.0 82755.8 11648.0 10941.9 28 0.367 3 0.571 0.938
S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小(元空间)
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
-堆内存统计
C:\Users\lujw0>jstat -gccapacity 1128
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
43520.0 690176.0 583168.0 25600.0 5632.0 461312.0 87552.0 1380352.0 138752.0 138752.0 0.0 1124352.0 87168.0 0.0 1048576.0 11648.0 31 3
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0C:第一个幸存区大小
S1C:第二个幸存区的大小
EC:伊甸园区的大小
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC:当前老年代大小
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代gc次数
FGC:老年代GC次数
-新生代垃圾回收统计
C:\Users\lujw0>jstat -gcnew 1128
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
25600.0 5632.0 0.0 5152.0 9 15 25600.0 461312.0 257085.0 31 0.401
S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
TT:对象在新生代存活的次数
MTT:对象在新生代存活的最大次数
DSS:期望的幸存区大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
-新生代内存统计
C:\Users\lujw0>jstat -gcnewcapacity 1128
NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
43520.0 690176.0 583168.0 229888.0 25600.0 229888.0 5632.0 689152.0 461312.0 31 3
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0CMX:最大幸存1区大小
S0C:当前幸存1区大小
S1CMX:最大幸存2区大小
S1C:当前幸存2区大小
ECMX:最大伊甸园区大小
EC:当前伊甸园区大小
YGC:年轻代垃圾回收次数
FGC:老年代回收次数
-老年代垃圾回收统计
C:\Users\lujw0>jstat -gcold 1128
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
87168.0 82884.4 11648.0 10941.9 138752.0 96971.8 32 3 0.571 0.983
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
OC:老年代大小
OU:老年代使用大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
-老年代内存统计
C:\Users\lujw0>jstat -gcoldcapacity 1128
OGCMN OGCMX OGC OC YGC FGC FGCT GCT
87552.0 1380352.0 138752.0 138752.0 32 3 0.571 0.983
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC:老年代大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
-元数据空间统计
C:\Users\lujw0>jstat -gcmetacapacity 1128
MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT
0.0 1124352.0 87168.0 0.0 1048576.0 11648.0 32 3 0.571 0.983
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
-总结垃圾回收统计
C:\Users\lujw0>jstat -gcutil 1128
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
91.76 0.00 95.12 69.89 95.09 93.94 32 0.412 3 0.571 0.983
S0:幸存1区当前使用比例
S1:幸存2区当前使用比例
E:伊甸园区使用比例
O:老年代使用比例
M:元数据区使用比例
CCS:压缩使用比例
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
2.3、Jmap(常用)
此命令可以产看内存信息
-实例个数以及占有内存大小
C:\Users\lujw0>jmap -histo 1128 >./hmaplog.txt
num #instances #bytes class name
----------------------------------------------
1: 1246051 216721832 [C
2: 800697 19216728 java.lang.String
3: 19592 12175032 [B
4: 183451 7338040 java.util.LinkedHashMap$Entry
5: 78428 6901664 java.lang.reflect.Method
6: 13787 5713720 [I
7: 201053 4825272 java.util.LinkedList$Node
8: 190438 4570512 com.intellij.rt.debugger.agent.CaptureStorage$HardKey
9: 105248 4209920 org.springframework.boot.devtools.filewatch.FileSnapshot
10: 129555 4145760 java.io.File
11: 36369 4074608 [Ljava.util.HashMap$Node;
12: 80872 3844216 [Ljava.lang.String;
13: 119361 3819552 java.util.concurrent.ConcurrentHashMap$Node
14: 107645 3444640 java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
15: 53509 2703504 [Ljava.lang.Object;
16: 80417 2573344 java.util.HashMap$Node
17: 35803 2004968 java.util.LinkedHashMap
18: 17368 1933400 java.lang.Class
19: 51969 1663008 java.lang.ref.WeakReference
20: 1122 1466832 [Ljava.util.concurrent.ConcurrentHashMap$Node;
21: 52470 1259280 java.util.ArrayList
22: 57148 1256584 [Ljava.lang.Class;
23: 15724 1132128 java.lang.reflect.Field
num:序号
instances:实例数量
bytes:占用空间大小
class name:类名称
-堆信息
C:\Users\lujw0>jmap -heap 1128
Attaching to process ID 1128, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.102-b14
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 2120220672 (2022.0MB)
NewSize = 44564480 (42.5MB)
MaxNewSize = 706740224 (674.0MB)
OldSize = 89653248 (85.5MB)
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 = 415760384 (396.5MB)
used = 364749400 (347.85213470458984MB)
free = 51010984 (48.647865295410156MB)
87.73067710077927% used
From Space:
capacity = 5242880 (5.0MB)
used = 5046320 (4.8125457763671875MB)
free = 196560 (0.1874542236328125MB)
96.25091552734375% used
To Space:
capacity = 23068672 (22.0MB)
used = 0 (0.0MB)
free = 23068672 (22.0MB)
0.0% used
PS Old Generation
capacity = 142082048 (135.5MB)
used = 99299144 (94.69904327392578MB)
free = 42782904 (40.80095672607422MB)
69.88859282208544% used
42219 interned Strings occupying 4803176 bytes.
-堆内存的dump 文件
C:\Users\lujw0>jmap -dump:format=b,file=xbootdump.hprof 1128
Dumping heap to C:\Users\lujw0\xbootdump.hprof ...
Heap dump file created
也可以设置内存溢出自动导出dump文件(内存很大的时候,可能会导不出来)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ (路径)
可以用jvisualvm命令工具导入该dump文件分析
C:\Users\lujw0>jvisualvm
输入上述命令之后就会打开jdk 自带的内存分析工具jvisualvm


2.4、Jstack
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是非常有用的。
C:\Users\lujw0>jstack 1128
2020-02-22 12:16:36
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.102-b14 mixed mode):
"RMI TCP Connection(6)-192.168.5.83" #203 daemon prio=5 os_prio=0 tid=0x00000000211cc000 nid=0x38d0 runnable [0x000000002b66d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000ee61a020> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:550)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1/1653161508.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
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)
"JMX server connection timeout 202" #202 daemon prio=5 os_prio=0 tid=0x00000000211c4800 nid=0x3a30 in Object.wait() [0x000000002b36f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x00000000ee610a10> (a [I)
at java.lang.Thread.run(Thread.java:745)
用jstack查找死锁,见如下示例,也可以用jvisualvm查看死锁
新写一个java 死锁的程序
public class DeadLockTest {
public static Object lock1 = new Object();
public static Object lock2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
try {
System.out.println("thread1 开始执行");
Thread.sleep(500);
} catch (Exception e) {
}
synchronized (lock2) {
System.out.println("thread1 执行结束");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
try {
System.out.println("thread2 开始执行");
Thread.sleep(500);
} catch (Exception e) {
}
synchronized (lock1) {
System.out.println("thread2 执行结束");
}
}
}).start();
}
}
通过jstack +进程id 也可以查看
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00000000181305a8 (object 0x00000000d6157ef0, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000000001812dc68 (object 0x00000000d6157f00, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.spring.study.user.test.DeadLockTest.lambda$main$1(DeadLockTest.java:33)
- waiting to lock <0x00000000d6157ef0> (a java.lang.Object)
- locked <0x00000000d6157f00> (a java.lang.Object)
at com.spring.study.user.test.DeadLockTest$$Lambda$2/1792845110.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at com.spring.study.user.test.DeadLockTest.lambda$main$0(DeadLockTest.java:21)
- waiting to lock <0x00000000d6157f00> (a java.lang.Object)
- locked <0x00000000d6157ef0> (a java.lang.Object)
at com.spring.study.user.test.DeadLockTest$$Lambda$1/716143810.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
通过jvisualvm 查看死锁

远程连接jvisualvm
启动普通的jar程序JMX端口配置:
java -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar foo.jar
tomcat的JMX配置
JAVA_OPTS=-Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
jvisualvm远程连接服务需要在远程服务器上配置host(连接ip 主机名),并且要关闭防火墙

jstack找出占用cpu最高的堆栈信息
1,使用命令top -p <pid> ,显示你的java进程的内存情况,pid是你的java进程号,比如4977
2,按H,获取每个线程的内存情况
3,找到内存和cpu占用最高的线程tid,比如4977
4,转为十六进制得到 0x1371 ,此为线程id的十六进制表示
5,执行 jstack 4977|grep -A 10 1371,得到线程堆栈信息中1371这个线程所在行的后面10行
6,查看对应的堆栈信息找出可能存在问题的代码