我们在企业级Java开发的过程中有时会遇到以下问题:
- 内存泄漏
- 线程死锁
- 锁抢占
- CPU占用过高
- 等等
JVM提供了一些命令工具可以帮助我们来定位这些问题:
1. Jps(Java Virtual Machine Process Status Tool)
它主要用来输出JVM中正在运行的进程状态信息。其语法格式如下:
usage: jps [-help] jps [-q] [-mlvV] [<hostid>] Definitions: <hostid>: <hostname>[:<port>]
Definitions中的host如果不指定,就代表本机。
其参数说明如下:
-q | 只输出进程号,不输出类名,jar名和main方法的传入参数。 |
-m | 输出传入main方法的参数。 |
-l | 输出main类或Jar的全限定名。 |
-v | 输出传入JVM的参数。 |
2. Jstack
jstack主要用来查看某个Java进程内所有线程的堆栈信息。其语法格式如下:
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可以通过线程堆栈信息来定位到具体代码。比如有一个线程CPU消耗特别高,如何查呢?具体方式如下:
- 根据linux命令:ps -ef | grep java 来查到需要定位的jvm进程号<pid>。
- 使用linux命令:top -Hp <pid> 来查到CPU使用最高的线程号。并将该线程号转换为16进制。
- 通过jvm命令:jstack -l <pid> > aaa.log 将该JVM进程的堆栈信息写入aaa.log文件中。
- 在aaa.log中查找我们算出的16进制的那个线程号。找到的堆栈信息就是该线程的堆栈信息。
3. jmap
jmap可以查看JVM中堆内存的使用情况。其使用语法如下:
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 -histo[:live] <pid> 查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象,如下所示:
172.20.120.15:hadoop@sz-pg-app-hadoop-001:/home/hadoop]$ jmap -histo:live 22651 | more num #instances #bytes class name ---------------------------------------------- 1: 14798 37768024 [I 2: 65877 29211512 [C 3: 6239 13987208 [B 4: 75269 4165384 [Ljava.lang.Object; 5: 71952 2878080 java.lang.ref.Finalizer 6: 56021 2240840 org.apache.commons.dbcp2.DelegatingPreparedStatement 7: 116128 1858048 java.lang.Object 8: 54438 1742016 java.util.HashMap$Node 9: 69013 1656312 java.util.ArrayList 10: 62762 1506288 java.lang.String 11: 11865 1325728 java.lang.Class 12: 18610 1323840 [Ljava.util.HashMap$Node; 13: 8492 1222848 org.jboss.netty.channel.socket.nio.NioClientSocketChannel 14: 30941 990112 java.util.concurrent.ConcurrentHashMap$Node 15: 8675 971600 sun.nio.ch.SocketChannelImpl 16: 17303 830544 java.util.HashMap 17: 34456 826944 java.net.InetSocketAddress$InetSocketAddressHolder 18: 7312 818944 java.net.SocksSocketImpl 19: 8492 747296 org.jboss.netty.handler.codec.http.HttpClientCodec$Decoder 20: 17008 680320 org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext 21: 25518 612432 java.util.concurrent.ConcurrentLinkedQueue$Node 22: 34456 551296 java.net.InetSocketAddress 23: 359 499168 [Ljava.nio.ByteBuffer; 24: 8494 475664 org.jboss.netty.util.HashedWheelTimer$HashedWheelTimeout 25: 5111 449768 java.lang.reflect.Method 26: 17198 412752 java.util.concurrent.ConcurrentLinkedQueue 27: 8492 407616 org.jboss.netty.channel.AbstractChannel$ChannelCloseFuture上面那几个class name都是啥意思呢?
B | byte | 带符号的byte |
C | char | Unicode字符 |
D | double | 双精度浮点数 |
F | float | 单精度浮点数 |
I | int | 32位整数 |
J | long | 64位整数 |
S | short | 16位整数 |
Z | boolean | true or false |
LClassname | reference | 引用类型 Ljava/lang/String 表示String Ljava/lang/Integer 表示Integer |
[ | reference | 数组类型,例如 [I 表示 int[] [Ljava/lang/Object 表示Object[] [[[D 表示 double[][][] |
4. jstat
jstat是JVM的统计监测工具。其语法格式如下:
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 -class pid:显示加载class的数量,及所占空间等信息。
jstat -compiler pid:显示VM实时编译的数量等信息。
jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。
jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推, OC是old内纯的占用量。
jstat -gcnew pid:new对象的信息。
jstat -gcnewcapacity pid:new对象的信息及其占用量。
jstat -gcold pid:old对象的信息。
jstat -gcoldcapacity pid:old对象的信息及其占用量。
jstat -gcpermcapacity pid: perm对象的信息及其占用量。
jstat -gcutil pid:统计gc信息统计。
jstat -printcompilation pid:当前VM执行的信息。
举例如下:
172.20.120.15:hadoop@sz-pg-app-hadoop-001:/home/hadoop]$ jstat -gcutil 22651 1000 1000 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 63.70 72.08 4.31 97.42 96.27 72859 1655.000 6 1.480 1656.479 0.00 63.70 72.54 4.31 97.42 96.27 72859 1655.000 6 1.480 1656.479 0.00 63.70 72.76 4.31 97.42 96.27 72859 1655.000 6 1.480 1656.479 0.00 63.70 73.47 4.31 97.42 96.27 72859 1655.000 6 1.480 1656.479S0 — Heap上的 Survivor space 0 区已使用空间的百分比
S1 — Heap上的 Survivor space 1 区已使用空间的百分比
E — Heap上的 Eden space 区已使用空间的百分比
O — Heap上的 Old space 区已使用空间的百分比
P — Perm space 区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)