本篇文章根据作者最近一段时间的工作经历和阅读网络资料进而完成的总结。主要对JVM调试过程中使用的命令进行总结,并列举了一个在实际工作中出现的JVM调试场景进行讲解。
这里要说明一下,在线上环境是不存在用户界面的只有命令行界面,所以我们使用JMX在使用类似jconsole、jvisualvm(包括插件)这样的界面化程序进行调试实不可取的,只能使用多种命令结合的方式进行。
1、常用命令介绍
首先介绍在命令行模式下经常使用的java相关指令,以及它们经常搭配的各种参数,包括:jps、jstat、jinfo、jmap。这些命令中,又数jstat和jmap命令最为重要。
1.1、jps命令
jps命令主要用于查看有权访问的hotspot虚拟机下工作的java进程(默认为本操作系统),以及进程编号。使用方式如下:
usage: jps [-help]
jps [-q] [-mlvV] [<hostid>]
例如:
# jps
26032
251056 Jps
11640
143420
// 以上是当前操作系统正在于运行的java进程,注意那个“251056”,jps也是一个java进程。
jps可以使用的参数包括:
- -q :仅仅显示VM 标示,不显示jar,class, main参数等信息.
- m:输出当运行java进程主方法时,操作者传入的参数.
- l: 输出应用程序主类完整package名称或jar完整名称。实例如下:
# jps -l
26032
248736 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
11640
143420
247660 sun.tools.jps.Jps
- v: 列出jvm参数, 例如-Xms100m -Xmx500m……,使用示例如下:
# jps -v
26032 -Dosgi.requiredJavaVersion=1.8 -XX:+UseG1GC -XX:+UseStringDeduplication -Dosgi.requiredJavaVersion=1.8 -Xms256m -Xmx1024m
248736 RemoteTestRunner -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:63591 -ea -Dfile.encoding=UTF-8
264176 Jps -Denv.class.path=D:Program FilesJavajdk1.8.0_144 -Dapplication.home=D:Program FilesJavajdk1.8.0_144 -Xms8m
143420 -Dosgi.requiredJavaVersion=1.8 -Xms4G -Dosgi.module.lock.timeout=10 -Xverify:none -Dorg.eclipse.swt.browser.IEVersion=10001 -Xmx4G -javaagent:lombok.jar
- -V 输出通过.hotsportrc或-XX:Flags=指定的jvm参数
1.2、jinfo命令
jinfo命令可以用来查看正在运行的java进程的运行参数和环境参数;在一些特定情况下,还可以在运行时修改部分参数。使用格式如下:
Usage:
jinfo [option] <pid>
(to connect to running process)
jinfo [option] <executable <core>
(to connect to a core file)
jinfo [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
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
<no option> to print both of the above
-h | -help to print this help message
一个简单的使用示例如下所示:
# jinfo 248736
Attaching to process ID 248736, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
Java System Properties:
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.144-b01
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
………………………………为了节约篇幅,省略了一些信息
java.endorsed.dirs = D:Program FilesJavajdk1.8.0_144jrelibendorsed
line.separator =
java.io.tmpdir = C:UsersADMINI~1AppDataLocalTemp
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = D:Program FilesJavajdk1.8.0_144in;C:WINDOWSSunJavain;C:WINDOWSsystem32;C:WINDOWS;D:Program FilesJavajdk1.8.0_144jrein;D:/Program Files/Java/jdk1.8.0_144/bin/../jre/bin/server;D:/Program Files/Java/jdk1.8.0_144/bin/../jre/bin;D:/Program Files/Java/jdk1.8.0_144/bin/../jre/lib/amd64;C:WindowsSystem32;C:Windows;C:WindowsSystem32wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:Program FilesJavajdk1.8.0_144in;D:apache-maven-3.2.3in;F:hadoop-2.6.0-cdh5.4.4in;D:Program FilesJavajdk1.8.0_144in;D:Program Files (x86)Microsoft SQL Server100ToolsBinn;;.
………………………………为了节约篇幅,又省略了一些信息
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=264241152 -XX:MaxHeapSize=4213178368 -XX:MaxNewSize=1404043264 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=88080384 -XX:OldSize=176160768 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:63591 -ea -Dfile.encoding=UTF-8
注意,jinfo打印的各种参数分为两种类型,一种叫做系统环境参数,另一种叫做JVM参数(后面会讲到)。 以上示例中,那个“248736”参数就是指定的java进程的进程号,可以通过多种方式获得,例如通过jps命令。那么下面我们详细介绍一下jinfo命令的主要参数:
- flags
使用该命令参数,打印当前指定java进程中已经设定的所有JVM参数信息。使用方式类似如下(注意,以下示例方式中的“314360”是java进程号):
# jinfo -flags 314360
Attaching to process ID 314360, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=264241152 -XX:MaxHeapSize=4213178368 -XX:MaxNewSize=1404043264 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=88080384 -XX:OldSize=176160768 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:55792 -ea -Dfile.encoding=UTF-8
- -flag <name>
使用该命令参数,可以打印出指定的参数信息,使用方式类似如下:
// 只显示当前指定进程中-XX:MinHeapDeltaBytes参数的值
# jinfo -flag MinHeapDeltaBytes 314360
-XX:MinHeapDeltaBytes=524288
// 再来一个,只显示当前指定进程中-XX:MaxNewSize参数的设定值
# jinfo -flag MaxNewSize 314360
-XX:MaxNewSize=1404043264
- -sysprops
使用该命令参数,打印当前java进程中设定的系统环境参数。使用方式如下(注意,以下示例方式中的“314360”也是java进程号):
# jinfo -sysprops 314360
Attaching to process ID 314360, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.144-b01
………………………………为了节约篇幅,又省略了一些信息
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
- -flag [+|-] <name>
通过该命令参数,可以更改标记类型为“manageable”,且设置值为“bool”型的参数值,使用示例如下:
// 这个“XX:+PrintGC”参数设置值为“bool”型,所以可以通过这个参数向java进程增加设置信息
# jinfo -flag +PrintGC 314360
// 还可以通过类似命令,从当前java进程中减少相关的JVM参数
# jinfo -flag -PrintGC 314360
- -flag <name>=<value>
通过该命令参数,可以为一些JVM参数设定新的值,使用示例如下:
# jinfo -flag CMSWaitDuration=3000 314360
// 当我们再通过-flags命令参数查看时,就可以看到这个设定了,如下:
Attaching to process ID 314360, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
Non-default VM flags: -XX:CICompilerCount=4 -XX:CMSWaitDuration=3000 ……………………
………………
上文提到了,jinfo命令可以修改一部分java进程参数,那么哪些参数可以修改呢?可以通过以下命令来确认:
// windows 方式
# java -XX:+PrintFlagsFinal -version | findstr /i manageable
// Linux 方式
# java -XX:+PrintFlagsFinal -version | grep manageable
// 将列出的信息类似如下:
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
intx CMSAbortablePrecleanWaitMillis = 100 {manageable}
intx CMSTriggerInterval = -1 {manageable}
intx CMSWaitDuration = 2000 {manageable}
bool HeapDumpAfterFullGC = false {manageable}
bool HeapDumpBeforeFullGC = false {manageable}
bool HeapDumpOnOutOfMemoryError = false {manageable}
ccstr HeapDumpPath = {manageable}
uintx MaxHeapFreeRatio = 100 {manageable}
uintx MinHeapFreeRatio = 0 {manageable}
bool PrintClassHistogram = false {manageable}
bool PrintClassHistogramAfterFullGC = false {manageable}
bool PrintClassHistogramBeforeFullGC = false {manageable}
bool PrintConcurrentLocks = false {manageable}
bool PrintGC = false {manageable}
bool PrintGCDateStamps = false {manageable}
bool PrintGCDetails = false {manageable}
bool PrintGCID = false {manageable}
bool PrintGCTimeStamps = false {manageable}
注意,实际上“java -XX:+PrintFlagsFinal -version”命令可以找到所有的flag信息,但是我们只能对标记为“manageable”的flag信息进行修改。
============
(接下文)