linux环境,JAVA_HOME/bin目录中有很多有用的命令:jps、jstat、jinfo、jmap、jhat、jstack。本文以监听2181端口的zookeeper应用为例讲解。
特别提醒下,在windows平台,这些命令以.exe结尾,也都可以在cmd命令行窗口执行。
jps:虚拟机进程状况工具
jps -mlv
如下:
[root@centos4 bin]# jps -mlv 1366 org.apache.zookeeper.server.quorum.QuorumPeerMain ../config/zookeeper.properties -Xmx512M -Xms512M -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+DisableExplicitGC -Djava.awt.headless=true -Xloggc:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs/zookeeper-gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dkafka.logs.dir=/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs -Dlog4j.configuration=file:./../config/log4j.properties 2839 kafka.Kafka ../config/server.properties -Xmx1G -Xms1G -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+DisableExplicitGC -Djava.awt.headless=true -Xloggc:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs/kafkaServer-gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dkafka.logs.dir=/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs -Dlog4j.configuration=file:./../config/log4j.properties 6167 sun.tools.jps.Jps -mlv -Dapplication.home=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64 -Xms8m
jstat:虚拟机统计信息监视工具
[root@centos4 bin]# jstat invalid argument count Usage: jstat -help|-options jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] Definitions: <option> An option reported by the -options option <vmid> Virtual Machine Identifier. A vmid takes the following form: <lvmid>[@<hostname>[:<port>]] Where <lvmid> is the local vm identifier for the target Java virtual machine, typically a process id; <hostname> is the name of the host running the target Java virtual machine; and <port> is the port number for the rmiregistry on the target host. See the jvmstat documentation for a more complete description of the Virtual Machine Identifier. <lines> Number of samples between header lines. <interval> Sampling interval. The following forms are allowed: <n>["ms"|"s"] Where <n> is an integer and the suffix specifies the units as milliseconds("ms") or seconds("s"). The default units are "ms". <count> Number of samples to take before terminating. -J<flag> Pass <flag> directly to the runtime system.
可选的option可通过jstat options查看,如下:
[root@centos4 bin]# jstat -options -class -compiler -gc -gccapacity -gccause -gcmetacapacity -gcnew -gcnewcapacity -gcold -gcoldcapacity -gcutil -printcompilation
最常用的是-gcutil。
jinfo:Java配置信息工具
[root@centos4 app]# jinfo 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后面如果不跟任何option,直接跟pid的话,会打印出VM信息和系统信息,最全。如下:
[root@centos4 app]# jinfo 1366 Attaching to process ID 1366, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.191-b12 Java System Properties: com.sun.management.jmxremote.authenticate = false java.runtime.name = OpenJDK Runtime Environment java.vm.version = 25.191-b12 sun.boot.library.path = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/lib/amd64 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 = OpenJDK 64-Bit Server VM sun.java.launcher = SUN_STANDARD user.country = US user.dir = /home/koushengrui/app/kafka_2.11-0.10.2.0/bin java.vm.specification.name = Java Virtual Machine Specification java.runtime.version = 1.8.0_191-b12 os.arch = amd64 java.endorsed.dirs = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/lib/endorsed line.separator = java.vm.specification.vendor = Oracle Corporation os.name = Linux log4j.configuration = file:./../config/log4j.properties sun.jnu.encoding = UTF-8 java.library.path = /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib java.specification.name = Java Platform API Specification java.class.version = 52.0 sun.management.compiler = HotSpot 64-Bit Tiered Compilers os.version = 3.10.0-693.el7.x86_64 user.home = /root user.timezone = Asia/Shanghai java.awt.printerjob = sun.print.PSPrinterJob file.encoding = UTF-8 java.specification.version = 1.8 user.name = root java.class.path = :/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/aopalliance-repackaged-2.5.0-b05.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/argparse4j-0.7.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/connect-api-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/connect-file-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/connect-json-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/connect-runtime-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/connect-transforms-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/guava-18.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/hk2-api-2.5.0-b05.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/hk2-locator-2.5.0-b05.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/hk2-utils-2.5.0-b05.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-annotations-2.8.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-annotations-2.8.5.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-core-2.8.5.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-databind-2.8.5.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-jaxrs-base-2.8.5.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-jaxrs-json-provider-2.8.5.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jackson-module-jaxb-annotations-2.8.5.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/javassist-3.20.0-GA.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/javax.annotation-api-1.2.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/javax.inject-1.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/javax.inject-2.5.0-b05.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/javax.servlet-api-3.1.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/javax.ws.rs-api-2.0.1.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-client-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-common-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-container-servlet-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-container-servlet-core-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-guava-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-media-jaxb-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jersey-server-2.24.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-continuation-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-http-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-io-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-security-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-server-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-servlet-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-servlets-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jetty-util-9.2.15.v20160210.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/jopt-simple-5.0.3.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka_2.11-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka_2.11-0.10.2.0-sources.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka_2.11-0.10.2.0-test-sources.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka-clients-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka-log4j-appender-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka-streams-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka-streams-examples-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/kafka-tools-0.10.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/log4j-1.2.17.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/lz4-1.3.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/metrics-core-2.2.0.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/osgi-resource-locator-1.0.1.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/reflections-0.9.10.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/rocksdbjni-5.0.1.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/scala-library-2.11.8.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/scala-parser-combinators_2.11-1.0.4.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/slf4j-api-1.7.21.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/slf4j-log4j12-1.7.21.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/snappy-java-1.1.2.6.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/validation-api-1.1.0.Final.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/zkclient-0.10.jar:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../libs/zookeeper-3.4.9.jar kafka.logs.dir = /home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs java.vm.specification.version = 1.8 sun.java.command = org.apache.zookeeper.server.quorum.QuorumPeerMain ../config/zookeeper.properties java.home = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre user.language = en java.vm.info = mixed mode java.version = 1.8.0_191 file.separator = / VM Flags: Non-default VM flags: -XX:CICompilerCount=4 -XX:ConcGCThreads=2 -XX:+DisableExplicitGC -XX:G1HeapRegionSize=1048576 -XX:InitialHeapSize=536870912 -XX:InitiatingHeapOccupancyPercent=35 -XX:+ManagementServer -XX:MarkStackSize=4194304 -XX:MaxGCPauseMillis=20 -XX:MaxHeapSize=536870912 -XX:MaxNewSize=321912832 -XX:MinHeapDeltaBytes=1048576 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC Command line: -Xmx512M -Xms512M -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+DisableExplicitGC -Djava.awt.headless=true -Xloggc:/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs/zookeeper-gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dkafka.logs.dir=/home/koushengrui/app/kafka_2.11-0.10.2.0/bin/../logs -Dlog4j.configuration=file:./../config/log4j.properties
jmap:Java堆内存映射工具
[root@centos4 bin]# jmap 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:打印堆信息。从中可以看出使用的垃圾收集器、堆的配置及其使用情况。如下:
[root@centos4 bin]# jmap -heap 1366
Attaching to process ID 1366, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.191-b12
using thread-local object allocation.
Garbage-First (G1) GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 536870912 (512.0MB)
NewSize = 1363144 (1.2999954223632812MB)
MaxNewSize = 321912832 (307.0MB)
OldSize = 5452592 (5.1999969482421875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 1048576 (1.0MB)
Heap Usage:
G1 Heap:
regions = 512
capacity = 536870912 (512.0MB)
used = 1856512 (1.7705078125MB)
free = 535014400 (510.2294921875MB)
0.34580230712890625% used
G1 Young Generation:
Eden Space:
regions = 0
capacity = 28311552 (27.0MB)
used = 0 (0.0MB)
free = 28311552 (27.0MB)
0.0% used
Survivor Space:
regions = 0
capacity = 0 (0.0MB)
used = 0 (0.0MB)
free = 0 (0.0MB)
0.0% used
G1 Old Generation:
regions = 2
capacity = 508559360 (485.0MB)
used = 1856512 (1.7705078125MB)
free = 506702848 (483.2294921875MB)
0.36505315721649484% used
3009 interned Strings occupying 242720 bytes.
jmap -histo pid:打印堆中的对象信息。jmap -histo:live:打印堆中存活的对象信息。如下:
[root@centos4 bin]# jmap -histo 1366 num #instances #bytes class name ---------------------------------------------- 1: 6703 509448 [C 2: 910 452864 [I 3: 1889 214352 java.lang.Class 4: 525 207248 [B 5: 6665 159960 java.lang.String 6: 2816 110784 [Ljava.lang.Object; ........................................................ 725: 1 16 sun.util.resources.LocaleData 726: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl Total 39669 2380888
num是根据bytes由大到小排列的排名。instances表示同一个class name的对象的个数。bytes是同一个class name的对象的总大小。class name是全类名。
jmap -finalizerinfo pid:打印待回收的对象信息。如下:
[root@centos4 bin]# jmap -finalizerinfo 1366 Attaching to process ID 1366, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.191-b12 Number of objects pending for finalization: 0
jmap -dump:<dump-options>:dump堆信息,生成二进制的heap dump文件,俗称堆转储文件。dump是转储的意思。dump文件名可以自定义。如:
[root@centos4 bin]# jmap -dump:format=b,file=zookeeper_201907112135.dump 1366 Dumping heap to /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/bin/zookeeper_201907112135.dump ... Heap dump file created
heap dump文件怎么用呢?由于heap dump文件是二进制文件,所以不能直接用文本编辑器打开。把heap dump文件从服务器down下来后,常用打开方式有两种:
用VisualVM打开或者用MAT打开。
用VisualVM打开步骤:双击JAVA_HOME/bin目录中的jvisualvm.exe打开Java VisualVM工具,点击左上角打开,装入,文件类型选择堆 Dump,然后选择刚刚的堆转储文件,就打开了。然后在概要处就可以看到基本信息、环境、系统属性以及堆转储上的线程信息,在类处可以看到所有的类以及每个类的实例数以及各类实例大小和占堆空间的比例。
如果dump文件特别大,就需要用MAT打开了。MAT全称是Eclipse Memory Analyzer,是eclipse官方出的一个独立插件。从官网下载好后,解压,直接双击MemoryAnalyzer.exe即可运行,不用依赖eclipse。左上角File,Open Heap Dump,选择刚刚的堆转储文件,打开。在Overview中可以看到有Actions、Reports、Step By Step,Actions下面有Histogram(列出了各类实例数量及占用内存大小)、Dominator Tree(列出了最大的对象)、Top Consumers(根据类名和包名分组,打印出最昂贵的对象)。Reports下面有Leak Suspects(列出了可能的内存泄露点)。
jstack:java堆栈跟踪工具
[root@centos4 bin]# jstack Usage: 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) Options: -F to force a thread dump. Use when jstack <pid> does not respond (process is hung) -m to print both java and native frames (mixed mode) -l long listing. Prints additional information about locks -h or -help to print this help message
jstack pid:dump运行的进程的线程信息。如果进程hung住了,需要加-F参数来强制dump。jstack -F pid:dump hung住进程的线程信息。这两个命令都默认把信息输出到当前命令行,我们一般都会输出到指定文件,jstack pid > thread201907121424.dump。这样就会在当前目录中生成thread201907121424.dump文件。down下来分析即可。dump线程生成的文件一般称为线程转储文件。线程转储文件可以直接用文本编辑器如notepad++打开,打开后可以看到dump瞬间所有的线程及其状态。由此可知,当我们自己创建线程或者线程池时,给线程命名是多么好的习惯啊,可以快速在大量的线程中找到自己命名的线程。从中还可以看到大量的Unsafe、LockSupport、AQS、CountDownLatch的API,所以学好这些类是必需的。