欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

探索Java内置的性能检测神器:jmap

最编程 2024-02-10 14:42:32
...

本文继续介绍Java自带的性能监测工具,本文使用jmap工具来玩~

jmap (Java Memory Map) 命令可以生成Java应用程序的堆快照和对象统计信息,对生成的堆快照进行分析,可以分析堆中对象所占用内存的情况,检查大对象等~

先使用jmap -help查看一下jmap命令的基本语法以及选择项(option)说明~

[root@dev18 ~]# jmap -help
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
    -permstat            to print permanent generation 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
[root@dev18 ~]#

jmap基本语法:

jmap [option] <pid>

jmap需要pid,所以需要和jps配合使用,也就是先使用jps获取pid信息,然后使用jmap来处理~

[root@dev18 ~]# jps -l
1656 org.elasticsearch.bootstrap.Elasticsearch
12905 org.apache.zookeeper.server.quorum.QuorumPeerMain
4308 /srv/activemq/apache-activemq-5.14.3//bin/activemq.jar
27265 sun.tools.jps.Jps
[root@dev18 ~]# 

接下来,本文使用Zookeeper的服务进程为例,其pid为12905

使用 jmap -heap 12905打印java heap的情况,如

[root@dev18 ~]# jmap -heap 12905
Attaching to process ID 12905, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.71-b01

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 0
   MaxHeapFreeRatio = 100
   MaxHeapSize      = 1004535808 (958.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 15204352 (14.5MB)
   used     = 12229848 (11.663291931152344MB)
   free     = 2974504 (2.8367080688476562MB)
   80.43649607691272% used
From Space:
   capacity = 524288 (0.5MB)
   used     = 32768 (0.03125MB)
   free     = 491520 (0.46875MB)
   6.25% used
To Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
PS Old Generation
   capacity = 41418752 (39.5MB)
   used     = 3584192 (3.41815185546875MB)
   free     = 37834560 (36.08184814453125MB)
   8.65354900118671% used
PS Perm Generation
   capacity = 22020096 (21.0MB)
   used     = 8938800 (8.524703979492188MB)
   free     = 13081296 (12.475296020507812MB)
   40.59382847377232% used

2776 interned Strings occupying 230000 bytes.
[root@dev18 ~]# 

使用 jmap -histo打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。

下面的例子使用jmap生成pid为12905的Java程序的对象统计信息(直方图的形式),并将生成的统计信息输出到时/usr/local目录下的12905.histo文件中,如:

[root@dev18 ~]# jmap -histo 12905 >/usr/local/12905.histo

打开12905.histo文件,查看详细的信息如:

[root@dev18 ~]# vim /usr/local/12905.histo 
 num     #instances         #bytes  class name
----------------------------------------------
   1:         30204        5384536  [B
   2:         17521        2252160  <methodKlass>
   3:         17521        2186552  <constMethodKlass>
   4:          1515        1644272  <constantPoolKlass>
   5:         39568        1582720  java.util.HashMap$KeyIterator
   6:         10809        1457680  [C
   7:          1515        1040840  <instanceKlassKlass>
   8:          1368        1032128  <constantPoolCacheKlass>
   9:         40162         919944  [Ljava.lang.Object;
  10:         36461         875064  java.util.ArrayList
  11:         35427         850248  java.lang.Long
  12:         15953         765744  java.nio.HeapByteBuffer
  13:          5384         387648  org.apache.zookeeper.server.Request
  14:         11669         373408  java.util.HashMap$Entry
  15:          3771         301296  [Ljava.util.HashMap$Entry;
  16:           612         296376  [I
  17:          5687         272976  java.util.HashMap
  18:          3805         254448  [S
  19:          7029         224928  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
  20:           453         203136  <methodDataKlass>
  21:          7138         171312  java.util.concurrent.LinkedBlockingQueue$Node
  22:          7008         168192  java.lang.String
  23:          1671         161696  java.lang.Class
  24:          2507         133624  [[I
  25:          5223         125352  java.util.Collections$UnmodifiableRandomAccessList
  26:          3513         112416  java.io.DataInputStream
  27:          3513         112416  java.io.DataOutputStream
  28:          3511         112352  org.apache.zookeeper.proto.ReplyHeader
  29:          1872          89856  org.apache.zookeeper.txn.TxnHeader
  30:          5486          87776  java.util.HashSet
  31:          3513          84312  org.apache.jute.BinaryOutputArchive
  32:          3512          84288  java.io.ByteArrayOutputStream
  33:           139          75616  <objArrayKlassKlass>
  34:          1506          72288  org.apache.zookeeper.KeeperException$NodeExistsException
  35:          1871          59872  org.apache.zookeeper.server.quorum.QuorumPacket
  36:          3561          56976  java.util.HashMap$KeySet
  37:          3513          56208  org.apache.zookeeper.server.ByteBufferInputStream
  38:          3513          56208  org.apache.jute.BinaryInputArchive
  39:          3512          56192  org.apache.zookeeper.server.SessionTrackerImpl$SessionSet
  40:          1873          44952  java.util.LinkedList$Node
  41:          1871          44904  org.apache.zookeeper.server.quorum.Leader$Proposal
  42:           516          41280  java.lang.reflect.Method
  43:          1045          33440  java.util.concurrent.ConcurrentHashMap$HashEntry
  44:          1694          27104  java.lang.Object
  45:          1506          24096  org.apache.zookeeper.txn.ErrorTxn
  46:           106          16960  org.apache.zookeeper.server.NIOServerCnxn
  47:           426          13632  java.util.concurrent.locks.ReentrantLock$NonfairSync
  48:           230          12704  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;

#instances, #bytes以及class name列说明:

instances列:表示当前类有多少个实例。

bytes列:说明当前类的实例总共占用了多少个字节

class name列:表示的就是当前类的名称,class name 解读:

   B代表byte 

   C代表char 

   D代表double 

   F代表float 

   I代表int 

   J代表long 

   Z代表boolean 

前边有[代表数组,[I 就相当于int[] 

对象用[L+类名表示 

也可以不生成文件,直接使用jmap -histo 12905查看,因为内容比较多,可以采用添加| more来限定~

[root@dev18 ~]# jmap -histo 12905 | more

 num     #instances         #bytes  class name
----------------------------------------------
   1:         30330        5407864  [B
   2:         17521        2252160  <methodKlass>
   3:         17521        2186552  <constMethodKlass>
   4:          1515        1644272  <constantPoolKlass>
   5:         39770        1590800  java.util.HashMap$KeyIterator
   6:         10827        1460848  [C
   7:          1515        1040840  <instanceKlassKlass>
   8:          1368        1032128  <constantPoolCacheKlass>
   9:         40346         923032  [Ljava.lang.Object;
  10:         36645         879480  java.util.ArrayList
  11:         35608         854592  java.lang.Long
  12:         16025         769200  java.nio.HeapByteBuffer
  13:          5402         388944  org.apache.zookeeper.server.Request
  14:         11723         375136  java.util.HashMap$Entry
  15:           613         357464  [I
  16:          3789         302736  [Ljava.util.HashMap$Entry;
  17:          5705         273840  java.util.HashMap
  18:          3805         254448  [S
  19:          7065         226080  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
  20:           453         203136  <methodDataKlass>
  21:          7174         172176  java.util.concurrent.LinkedBlockingQueue$Node
  22:          7008         168192  java.lang.String
  23:          1671         161696  java.lang.Class
  24:          2507         133624  [[I
  25:          5241         125784  java.util.Collections$UnmodifiableRandomAccessList
  26:          3531         112992  java.io.DataInputStream
  27:          3531         112992  java.io.DataOutputStream
  28:          3529         112928  org.apache.zookeeper.proto.ReplyHeader
  29:          1872          89856  org.apache.zookeeper.txn.TxnHeader
  30:          5504          88064  java.util.HashSet
  31:          3531          84744  org.apache.jute.BinaryOutputArchive
  32:          3530          84720  java.io.ByteArrayOutputStream
  33:           139          75616  <objArrayKlassKlass>
  34:          1506          72288  org.apache.zookeeper.KeeperException$NodeExistsException
  35:          1871          59872  org.apache.zookeeper.server.quorum.QuorumPacket
  36:          3579          57264  java.util.HashMap$KeySet
  37:          3531          56496  org.apache.zookeeper.server.ByteBufferInputStream
  38:          3531          56496  org.apache.jute.BinaryInputArchive
  39:          3530          56480  org.apache.zookeeper.server.SessionTrackerImpl$SessionSet
  40:          1873          44952  java.util.LinkedList$Node
  41:          1871          44904  org.apache.zookeeper.server.quorum.Leader$Proposal
  42:           516          41280  java.lang.reflect.Method
  43:          1045          33440  java.util.concurrent.ConcurrentHashMap$HashEntry
  44:          1694          27104  java.lang.Object
  45:          1506          24096  org.apache.zookeeper.txn.ErrorTxn
  46:           106          16960  org.apache.zookeeper.server.NIOServerCnxn
  47:           426          13632  java.util.concurrent.locks.ReentrantLock$NonfairSync
  48:           230          12704  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
  49:           308          12320  java.lang.ref.SoftReference

使用jmap -permstat 12905打印permanent generation heap情况

[root@dev18 ~]# jmap -permstat 12905
Attaching to process ID 12905, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.71-b01
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader  classes  bytes  parent_loader  alive?  type

<bootstrap>  1267  7343336    null    live  <internal>
0x00000000c4292130  1  3048    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c420b210  0  0    null    dead  sun/misc/Launcher$ExtClassLoader@0x00000000bf1c0120
0x00000000c4292170  1  1888    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c42921b0  1  1888    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c4292358  2  32144    null    dead  javax/management/remote/rmi/NoCallStackClassLoader@0x00000000bf546b68
0x00000000c42921f0  1  1888    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c420b1c0  401  2657256  0x00000000c420b210  dead  sun/misc/Launcher$AppClassLoader@0x00000000bf21a9c8
0x00000000c42920e0  4  13776    null    dead  javax/management/remote/rmi/NoCallStackClassLoader@0x00000000bf546b68
0x00000000c4292318  1  3048    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c42922d8  1  1888    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c4292298  1  3048    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8
0x00000000c4312bc8  0  0  0x00000000c420b1c0  dead  java/util/ResourceBundle$RBClassLoader@0x00000000bf6dce70
0x00000000c4292258  1  3056    null    dead  sun/reflect/DelegatingClassLoader@0x00000000bf04ffc8

total = 14  1682  10066264      N/A      alive=1, dead=13      N/A    
[root@dev18 ~]# 

jmap还有一个功能是可以手工生成指定程序的堆快照文件~ 使用-dump选项~

如:

jmap -dump:format=b,file=/usr/local/12905.hprof 12905

该示例为pid为12905的程序生成一个二进制的dump文件,文件放置在/usr/local目录下, 名字为12905.hprof~

[root@dev18 ~]# jmap -dump:format=b,file=/usr/local/12905.hprof 12905
Dumping heap to /usr/local/12905.hprof ...
Heap dump file created
[root@dev18 ~]# 

针对这种产生的dump文件,可以使用JDK自带jhat(Java Heap Analyse Tool)小工具来查看,可以将对中的对象以html的形式展示,包括对象的数量、大小等信息,并支持对象查询语言 (OQL),jhat将会在下一篇文章中介绍~