我們在企業級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.479
S0 — 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 — 從應用程序啓動到採樣時用於垃圾回收的總時間(單位秒)