jps
jps(JavaVirtual Machine process Status Toll)查看当前java进程的小工具。
通过 jps -help查看具体有哪些用法。
usage: jps [-help]
jps [-q] [-mlvV] [<hostid>]
Definitions:
<hostid>: <hostname>[:<port>]
- -q:仅显示进程。
- -m:输出住函数传入的参数 就是在执行程序时从命令行输入的参数
- -l:输出应用程序主类完成package名称或jar完整名称。
- -v:列出jvm参数,启动时手动设置的。
笔者常用的为jps -lv能够输出进程ID、全限定主类名,jar包的完全路径和手动配置的JVM参数,如下: jps -lv
3433 sun.tools.jps.Jps -Dapplication.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home -Xms8m
1262 org.jetbrains.jps.cmdline.Launcher -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Dpreload.project.path=/Users/naigaipaopao/IdeaProjects/study -Dpreload.config.path=/Users/naigaipaopao/Library/Application Support/JetBrains/IntelliJIdea2021.3/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djdt.compiler.useSingleThread=true -Daether.connector.resumeDownloads=false -Dio.netty.initialSeedUniquifier=3850549903300846449 -Dfile.encoding=UTF-8 -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2021.3 -Didea.home.path=/Applications/IntelliJ IDEA.app/Contents -Didea.config.path=/Users/naigaipaopao/Library/Application Support/JetBrains/IntelliJIdea2021.3 -Didea.plugins.path=/Users/naigaipaopao/Library/Application Support/JetBrains/IntelliJIdea2021.3/plugins -Djps.log.dir=/Users/naigaipaopao/Library/Logs/JetBrains/IntelliJIdea2021.3/build-log -Djps.fallback.jdk.home=/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home -Djps.fallback.jdk.version=11.0.13 -Dio.netty.noUnsafe=true -Djava.io.tmpdir=/
1263 com.study.StudyApplication -XX:PreInflateSpin=10 -Xms100M -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=51029:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8
1183 -Xms128m -Xmx750m -XX:ReservedCodeCacheSize=512m -XX:+IgnoreUnrecognizedVMOptions -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:CICompilerCount=2 -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -ea -Dsun.io.useCanonCaches=false -Djdk.http.auth.tunneling.disabledSchemes="" -Djdk.attach.allowAttachSelf=true -Djdk.module.illegalAccess.silent=true -Dkotlinx.coroutines.debug=off -XX:ErrorFile=/Users/naigaipaopao/java_error_in_idea_%p.log -XX:HeapDumpPath=/Users/naigaipaopao/java_error_in_idea.hprof -Xmx1024m -javaagent:/Users/naigaipaopao/JetbrainsIdesCrack_5_3_1_KeepMyLic.jar -Djb.vmOptionsFile=/Users/naigaipaopao/Library/Application Support/JetBrains/IntelliJIdea2021.3/idea.vmoptions -Dsplash=true -Didea.home.path=/Applications/IntelliJ IDEA.app/Contents -Didea.jre.check=true -Didea.executable=idea -Djava.system.class.loader=com.intellij.util.lang.PathClassLoader -Didea.paths.selector=IntelliJIdea2021.3 -Didea.vendor.name=JetBrains
jstat
jstat(JVM statistics-Monitoring Tool),用于监视虚拟机各种运行状态信息的命令行工具。
它可以显示本地或者远程虚拟机中的类加载、内存、垃圾收集、JIT编译等运行数据,在没有 GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。
常用参数:
- -class (类加载器)
- -compiler (JIT)
- -gc (GC 堆状态)
- -gccapacity (各区大小)
- -gccause (最近一次 GC 统计和原因)
- -gcnew (新区统计)
- -gcnewcapacity (新区大小)
- -gcold (老区统计)
- -gcoldcapacity (老区大小)
- -gcpermcapacity (永久区大小)
- -gcutil (GC 统计汇总)
- -printcompilation (HotSpot 编译统计)
笔者常用的是jstat -gccapacity <pid> 1000 10
和jstat -gccause <pid> 1000 10
jstat -gccapacity
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
33792.0 698880.0 223232.0 10240.0 12800.0 195072.0 68608.0 1398272.0 68608.0 68608.0 0.0 1079296.0 35496.0 0.0 1048576.0 4776.0 8 2
- NGCMN:年轻代最小容量。
- NGCMX:年轻代最大容量。
- NGC:当前的年轻代容量。
- S0C:当前的from区容量。
- S1C:当前的to区容量。
- EC:当前的eden区容量。
- OGCMN:老年代最小容量。
- OGCMX:老年代最大容量。
- OGC:当前老年代容量。
- OC:当前old空间容量。
- MCMN:最小元空间容量。
- MCMX:最大元空间容量。
- MC:当前元空间容量。
- CCSMN:压缩的类空间最小容量。
- CCSMX:压缩的类空间最大容量。
- CCSC:当前压缩的类空间容量。
- YGC:年轻代GC的次数。
- FGC:全堆GC的次数。
jstat -gccause
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
0.00 0.00 83.70 26.53 95.73 92.72 8 0.111 2 0.072 0.183 Metadata GC Threshold No GC
- S0:from区利用率占当前容量的百分比。
- s1:to区利用率占当前容量的百分比。
- E:eden区利用率占当前容量的百分比。
- O:老年代区利用率占当前容量的百分比。
- M:元空间利用率占当前容量的百分比。
- CCS:压缩后的元空间利用率占当前容量的百分比。
- YGC:年轻代GC发生的次数。
- YGCT:年轻代回收的时间。
- FGC:全堆GC次数。
- FGCT:全堆GC的时间。
- GCT:GC花费的总时间。
- LGCC:上次GC的原因。
- GCC:当前GC的原因。
jinfo
jinfo(Configuration Info for Java)用于查看和修改虚拟机的参数。
Usage:
jinfo <option> <pid>
(to connect to a running process)
where <option> is one of:
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties System.getProperties()
<no option> to print both VM flags and system properties
-? | -h | --help | -help to print this help message
一般直接jinfo -flags <pid>
查看虚拟机参数。能修改的flag可以使用java -XX:+PrintFlagsFianl -version
查看manageable的参数表示可以运行时修改。
jmap
主要用于生产dump文件,还可以查询finalize执行队列、Java堆和永久代的详细信息,如空间使用率、当前使用的是那种收集器等。
Usage:
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)
where <option> is one of:
<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
常用的是jmap -heap <pid>
(jdk11需要使用jhsdb jmap --heap --pid <pid>
)和 jmap -dump:live,format=b,file=heap.bin <pid>
jstack
jstack(Stack Trace for Java)命令用于生成当前时刻的线程快照。线程快照就是当前虚拟机内每一条线程正在执行的方法的堆栈的集合,生成线程快照的主要目的是定位线程出现时间停顿的原因,入线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。
下面我们直接看上次《Thread源码阅读及相关问题》的死锁例子来看看:
package com.study.thread;
import lombok.SneakyThrows;
public class DeadLock {
public static void main(String[] args) {
Object lock1 = new Object();
Object lock2 = new Object();
Thread thread1 = new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
synchronized (lock1) {
System.out.println("thread1成功持有lock1");
Thread.sleep(1000);
synchronized (lock2) {
System.out.println("thread1成功持有lock2");
}
}
}
});
Thread thread2 = new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
synchronized (lock2) {
System.out.println("thread2成功持有lock2");
Thread.sleep(1000);
synchronized (lock1) {
System.out.println("thread2成功持有lock1");
}
}
}
});
thread1.start();
thread2.start();
}
}
像这样的死锁,项目比较大,是很难通过人工排查的,我们下面看看jstack <pid>
的输出:
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007f9d8d8142a8 (object 0x00000007957f0f10, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007f9d8d8118b8 (object 0x00000007957f0f20, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.study.thread.DeadLock$2.run(DeadLock.java:35)
- waiting to lock <0x00000007957f0f10> (a java.lang.Object)
- locked <0x00000007957f0f20> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.study.thread.DeadLock$1.run(DeadLock.java:19)
- waiting to lock <0x00000007957f0f20> (a java.lang.Object)
- locked <0x00000007957f0f10> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
这个告诉了你具体的代码行,等待的锁被谁持有就很容易定位到了。
特别放送-异常分析
如果仔细的读者可以发现一些问题:开始根据jps了解到,笔者自己手动设置了-xms即最小的堆空间。从jstat了解到一共发生了8次YGC,2次FGC。
为啥会发生8次YGC?
通过jstat -gccapactity
可以看到,年轻代最小的时候为33M,最大的时候为682M,当前年轻代占用218M。通过jstat -gccause
可以看到目前eden的使用率为83.7%。
项目只是启动,还没使用。很明显我们的设置的-xms比较小,我们可以设置为500M试下。
jstat -gccapacity:
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
170496.0 698880.0 209920.0 17408.0 20992.0 128512.0 341504.0 1398272.0 341504.0 341504.0 0.0 1087488.0 44072.0 0.0 1048576.0 5928.0 5 2
170496.0 698880.0 209920.0 17408.0 20992.0 128512.0 341504.0 1398272.0 341504.0 341504.0 0.0 1087488.0 44072.0 0.0 1048576.0 5928.0 5 2
170496.0 698880.0 209920.0 17408.0 20992.0 128512.0 341504.0 1398272.0 341504.0 341504.0 0.0 1087488.0 44072.0 0.0 1048576.0 5928.0 5 2
170496.0 698880.0 209920.0 17408.0 20992.0 128512.0 341504.0 1398272.0 341504.0 341504.0 0.0 1087488.0 44072.0 0.0 1048576.0 5928.0 5 2
170496.0 698880.0 209920.0 17408.0 20992.0 128512.0 341504.0 1398272.0 341504.0 341504.0 0.0 1087488.0 44072.0 0.0 1048576.0 5928.0 5 2
170496.0 698880.0 209920.0 17408.0 20992.0 128512.0 341504.0 1398272.0 341504.0 341504.0 0.0 1087488.0 44072.0 0.0 1048576.0 5928.0 5 2
jstat -gccause:
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 63.74 19.11 5.79 95.03 92.11 5 0.080 2 0.063 0.142 Allocation Failure No GC
0.00 63.74 19.11 5.79 95.03 92.11 5 0.080 2 0.063 0.142 Allocation Failure No GC
0.00 63.74 19.11 5.79 95.03 92.11 5 0.080 2 0.063 0.142 Allocation Failure No GC
0.00 63.74 19.11 5.79 95.03 92.11 5 0.080 2 0.063 0.142 Allocation Failure No GC
0.00 63.74 19.11 5.79 95.03 92.11 5 0.080 2 0.063 0.142 Allocation Failure No GC
可以发现,YGC变成了5次,FGC还是2次,从Metadata GC Threshold
变成了Allocation Failure
。
调整后年轻代最小的时候为166.5M,最大的时候为68.25M,当前年轻代占用205M。通过jstat -gccause
可以看到目前eden的使用率为19.11%。那为啥还会有5次YGC呢,那是因为默认开启了-XX:+UsePSAdaptiveSurvivorSizePolicy
会动态调整,调整是从小开始调整SurvivorSize直到一个合适的值并且因为只设置了-Xms所以整个堆分区都会进行动态调整直到找到一个合适的值,所以调整的过程中发生YGC是正常的,只要-Xms不要给的太小,不然会从一个很小的值开始调整。
为啥会发生2次FGC呢?
FGC发生的原因一般有老年代空间不足和Metaspace区内存达到阈值了,我们先分析下为啥当-Xms100M的时候会出现Metadata GC Threshold
。
我们先看看有关元空间有关的配置:
-XX:MetaspaceSize
:元空间初始化值,默认为20M。-XX:MaxMetaspaceSize
:默认为最大字节为2^64-1直接是最大容量。-XX:MinMetaspaceFreeRatio
:最小的空闲比率,默认为40%,如果比它小就需要进行扩容。-XX:MaxMetaspaceFreeRatio
:最大的空间比率,默认为70%,如果大于它就需要进行释放。-XX:MaxMetaspaceExpansion
:膨胀最大步长,默认为5.2M。-XX:MinMetaspaceExpansion
:膨胀最小步长,0.32M。
我们再看看发生Metadata GC Threshold
时的元空间情况:
- 最小为0M。
- 最大为1054M。
- 当前为34.7M。
- 当前M的占用率为95.73%。
马上又要扩容了,感觉是最小元空间太小了,下面我们试下,使用-Xms100M -XX:MetaspaceSize=100M,下面看看jstat -gccapacity
:
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
99.93 0.00 45.21 30.20 94.85 92.22 8 0.132 0 0.000 0.132 Allocation Failure No GC
99.93 0.00 45.21 30.20 94.85 92.22 8 0.132 0 0.000 0.132 Allocation Failure No GC
99.93 0.00 45.21 30.20 94.85 92.22 8 0.132 0 0.000 0.132 Allocation Failure No GC
99.93 0.00 45.21 30.20 94.85 92.22 8 0.132 0 0.000 0.132 Allocation Failure No GC
99.93 0.00 45.21 30.20 94.85 92.22 8 0.132 0 0.000 0.132 Allocation Failure No GC
可以发现没有发生FGC了。那么我们继续看看把参数设置成-Xms500M -XX:MetaspaceSize=100M:
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
99.99 0.00 9.59 2.84 95.13 93.12 4 0.148 0 0.000 0.148 Allocation Failure No GC
99.99 0.00 9.59 2.84 95.13 93.12 4 0.148 0 0.000 0.148 Allocation Failure No GC
99.99 0.00 9.59 2.84 95.13 93.12 4 0.148 0 0.000 0.148 Allocation Failure No GC
99.99 0.00 9.59 2.84 95.13 93.12 4 0.148 0 0.000 0.148 Allocation Failure No GC
99.99 0.00 9.59 2.84 95.13 93.12 4 0.148 0 0.000 0.148 Allocation Failure No GC
可以发现,YGC变成了4次,FGC变成了0次,说明修改-Xms和-XX:MetaspaceSize是有效的。
总结
- 我们可以通过jps了解到有哪些java进程在运行,并且可以看到手动配置的jvm参数
- 通过jstat我们可以了解到gc相关的信息(各个区的内存分配、使用率、gc原因等)。
- 我们可以通过jinfo查看和修改(manageable的参数)虚拟参数。
- 我们可以通过jmp产生dump文件用于分析,还可以了解当前使用的收集器和堆/永久代的详细信息。
- 我们可以通过jstack查看线程的快照,方便定位停留时间比较长的线程。