1 Star 0 Fork 1

wow / java-notes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
JVM调优工具.md 21.28 KB
一键复制 编辑 原始数据 按行查看 历史
wow 提交于 2021-03-26 15:26 . 分布式事务

JDK自带工具

我们介绍一下java 常用的 jvm 调优工具

jps - 列出Java进程

  • 打印出当前机器上的java进程

    jps

    输出

    E:\gitee-2\java-notes\java-nodes-project>jps
    14596 RemoteMavenServer
    4984 Jps
    13804
  • 输出传递给main方法的参数

    jps -m

    输出

    E:\gitee-2\java-notes\java-nodes-project>jps -m
    6272 Jps -m
    14596 RemoteMavenServer
    13804
  • 输出main.class 完整的 package 名,或者jar文件完整的路径名

    jps -l

    输出

    E:\gitee-2\java-notes\java-nodes-project>jps -l
    14596 org.jetbrains.idea.maven.server.RemoteMavenServer
    2104 sun.tools.jps.Jps
    13804
  • 输出传递给JVM的参数 -v

    jps -v

    输出

    E:\gitee-2\java-notes\java-nodes-project>jps -v
    14596 RemoteMavenServer -Djava.awt.headless=true -Didea.version==2018.3.2 -Xmx768m -Didea.maven.embedder.version=3.3.9 -Dfile.encoding=UTF-8
    9684 Jps -Dapplication.home=C:\1_my\software\java_jDK\1.8\jdk -Xms8m

以上参数都可以组合使用

jinfo-输出应用程序的信息

20210315201504

jstat-java的统计信息

jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]

**注意:**以下的统计空间单位,未标明的 都是KB

  1. 类加载统计

    命令

    jstat -class 19570

    结果 20210316074455

    解析:

    Loaded:加载class的数量
    Bytes:所占用空间大小
    Unloaded:未加载数量
    Bytes:未加载占用空间
    Time:时间
  2. 编译统计

    命令

    jstat -compiler 19570

    结果

    20210316074618

    解析

    Compiled:编译数量。
    Failed:失败数量
    Invalid:不可用数量
    Time:时间
    FailedType:失败类型
    FailedMethod:失败的方法
  3. 垃圾回收统计

    命令

    jstat -gc 19570

    结果 20210316074933 解析

    S0C:第一个幸存区的大小
    S1C:第二个幸存区的大小
    S0U:第一个幸存区的使用大小
    S1U:第二个幸存区的使用大小
    EC:伊甸园区的大小
    EU:伊甸园区的使用大小
    OC:老年代大小
    OU:老年代使用大小
    MC:方法区大小
    MU:方法区使用大小
    CCSC:压缩类空间大小
    CCSU:压缩类空间使用大小
    YGC:年轻代垃圾回收次数
    YGCT:年轻代垃圾回收消耗时间
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间
  4. 堆内存统计 命令:

    jstat -gccapacity 19570

    结果:

    20210316075036

    解析:

    NGCMN:新生代最小容量
    NGCMX:新生代最大容量
    NGC:当前新生代容量
    S0C:第一个幸存区大小
    S1C:第二个幸存区的大小
    EC:伊甸园区的大小
    OGCMN:老年代最小容量
    OGCMX:老年代最大容量
    OGC:当前老年代大小
    OC:当前老年代大小
    MCMN:最小元数据容量
    MCMX:最大元数据容量
    MC:当前元数据空间大小
    CCSMN:最小压缩类空间大小
    CCSMX:最大压缩类空间大小
    CCSC:当前压缩类空间大小
    YGC:年轻代gc次数
    FGC:老年代GC次数
  5. 新生代垃圾回收统计 命令:

    jstat -gcnew 19570

    结果:

    解析:

    S0C:第一个幸存区大小
    S1C:第二个幸存区的大小
    S0U:第一个幸存区的使用大小
    S1U:第二个幸存区的使用大小
    TT:对象在新生代存活的次数
    MTT:对象在新生代存活的最大次数
    DSS:期望的幸存区大小
    EC:伊甸园区的大小
    EU:伊甸园区的使用大小
    YGC:年轻代垃圾回收次数
    YGCT:年轻代垃圾回收消耗时间
  6. 新生代内存统计

    命令:

    jstat -gcnewcapacity 19570

    结果: 20210316082951

    解析:

    NGCMN:新生代最小容量
    NGCMX:新生代最大容量
    NGC:当前新生代容量
    S0CMX:最大幸存1区大小
    S0C:当前幸存1区大小
    S1CMX:最大幸存2区大小
    S1C:当前幸存2区大小
    ECMX:最大伊甸园区大小
    EC:当前伊甸园区大小
    YGC:年轻代垃圾回收次数
    FGC:老年代回收次数
  7. 老年代垃圾回收统计 命令:

    jstat -gcold 19570

    结果: 20210316083410

    解析:

    MC:方法区大小
    MU:方法区使用大小
    CCSC:压缩类空间大小
    CCSU:压缩类空间使用大小
    OC:老年代大小
    OU:老年代使用大小
    YGC:年轻代垃圾回收次数
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间
  8. 老年代内存统计 命令:

    jstat -gcoldcapacity 19570

    结果:

    20210316083533

    解析:

    OGCMN:老年代最小容量
    OGCMX:老年代最大容量
    OGC:当前老年代大小
    OC:老年代大小
    YGC:年轻代垃圾回收次数
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间
  9. JDK7 下 永久代空间统计

    命令:

    jstat -gcpermcapacity 19570

    结果: 20210316083630 解析:

    PGCMN:最小永久代容量
    PGCMX:最大永久代容量
    PGC:当前新生成的永久代空间大小
    PC :永久代空间大小
    YGC:年轻代垃圾回收次数
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间
  10. JDK8 下 元数据空间统计

    命令:

    jstat -gcmetacapacity 7172

    结果:

    MCMN       MCMX        MC       CCSMN      CCSMX       CCSC     YGC   FGC    FGCT     GCT
    0.0    33152.0    33152.0        0.0        0.0        0.0    12     0    0.000    0.736

    解析:

    MCMN:最小元数据容量
    MCMX:最大元数据容量
    MC:当前元数据空间大小
    CCSMN:最小压缩类空间大小
    CCSMX:最大压缩类空间大小
    CCSC:当前压缩类空间大小
    YGC:年轻代垃圾回收次数
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间
  11. 总结垃圾回收统计

    命令:

    jstat -gcutil 19570

    结果: 20210316084026 解析:

    S0:幸存1区当前使用比例
    S1:幸存2区当前使用比例
    E:伊甸园区使用比例
    O:老年代使用比例
    M:元数据区使用比例
    CCS:压缩使用比例
    YGC:年轻代垃圾回收次数
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间
  12. JVM编译方法统计

    命令:

    jstat -printcompilation 19570

    结果: 20210316084224

    解析:

    Compiled:最近编译方法的数量
    Size:最近编译方法的字节码数量
    Type:最近编译方法的编译类型。
    Method:方法名标识。

jstack-线程堆栈分析

jstack是jdk自带的线程堆栈分析工具,使用该命令可以查看或导出 java 应用程序中线程堆栈信息。

/opt/java8/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) 连接dump的文件
    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统计线程数

/opt/java8/bin/jstack -l 28367 | grep 'java.lang.Thread.State' | wc -l
  1. jstack 查看输出

    命令

    jstack -l 28367

    结果

    /opt/java8/bin/jstack -l 28367
    
    2019-06-25 15:04:46
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.77-b03 mixed mode):
    
    "Attach Listener" #453 daemon prio=9 os_prio=0 tid=0x00007f9f94001000 nid=0xf30 waiting on condition [0x0000000000000000]
    java.lang.Thread.State: RUNNABLE
    
    Locked ownable synchronizers:
            - None
    
    "grpc-default-executor-263" #452 daemon prio=5 os_prio=0 tid=0x00007f9f4c01f800 nid=0x9aa waiting on condition [0x00007f9f398bd000]
    java.lang.Thread.State: TIMED_WAITING (parking)
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x00000007400243f0> (a java.util.concurrent.SynchronousQueue$TransferStack)
            at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
            at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
            at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
            at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
            at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at java.lang.Thread.run(Thread.java:745)
    
    Locked ownable synchronizers:
            - None
  2. jstack统计线程数

    命令

    jstack -l 28367 | grep 'java.lang.Thread.State' | wc -l

  3. 检查cpu占用

    1. 首先使用top确认进程

      命令

      top

      输出

      Mem:  16333644k total,  9472968k used,  6860676k free,   165616k buffers
      Swap:        0k total,        0k used,        0k free,  6665292k cached
      
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND     
      17850 root      20   0 7588m 112m  11m S 100.7  0.7  47:53.80 java       
      1552 root      20   0  121m  13m 8524 S  0.7  0.1  14:37.75 AliYunDun   
      3581 root      20   0 9750m 2.0g  13m S  0.7 12.9 298:30.20 java        
          1 root      20   0 19360 1612 1308 S  0.0  0.0   0:00.81 init        
          2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd    
          3 root      RT   0     0    0    0 S  0.0  0.0   0:00.14 migration/0 
    2. 查看cpu占用高线程

      命令

      top -H -p 17850

      输出

      top - 17:43:15 up 5 days,  7:31,  1 user,  load average: 0.99, 0.97, 0.91
      Tasks:  32 total,   1 running,  31 sleeping,   0 stopped,   0 zombie
      Cpu(s):  3.7%us,  8.9%sy,  0.0%ni, 87.4%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
      Mem:  16333644k total,  9592504k used,  6741140k free,   165700k buffers
      Swap:        0k total,        0k used,        0k free,  6781620k cached
      
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
      17880 root      20   0 7588m 112m  11m R 99.9  0.7  50:47.43 java
      17856 root      20   0 7588m 112m  11m S  0.3  0.7   0:02.08 java
      17850 root      20   0 7588m 112m  11m S  0.0  0.7   0:00.00 java
      17851 root      20   0 7588m 112m  11m S  0.0  0.7   0:00.23 java
      17852 root      20   0 7588m 112m  11m S  0.0  0.7   0:02.09 java
      17853 root      20   0 7588m 112m  11m S  0.0  0.7   0:02.12 java
      17854 root      20   0 7588m 112m  11m S  0.0  0.7   0:02.07 java
    3. 转换线程ID

      命令

      printf "%x\n" 17880

      输出

      45d8
    4. 定位cpu占用线程

      命令

      jstack 17850|grep 45d8 -A 30

      输出

          
      "pool-1-thread-11" #20 prio=5 os_prio=0 tid=0x00007fc860352800 nid=0x45d8 runnable [0x00007fc8417d2000]
      java.lang.Thread.State: RUNNABLE
          at java.io.FileOutputStream.writeBytes(Native Method)
          at java.io.FileOutputStream.write(FileOutputStream.java:326)
          at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
          at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
          - locked <0x00000006c6c2e708> (a java.io.BufferedOutputStream)
          at java.io.PrintStream.write(PrintStream.java:482)
          - locked <0x00000006c6c10178> (a java.io.PrintStream)
          at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
          at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
          at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
          - locked <0x00000006c6c26620> (a java.io.OutputStreamWriter)
          at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
          at java.io.PrintStream.write(PrintStream.java:527)
          - eliminated <0x00000006c6c10178> (a java.io.PrintStream)
          at java.io.PrintStream.print(PrintStream.java:597)
          at java.io.PrintStream.println(PrintStream.java:736)
          - locked <0x00000006c6c10178> (a java.io.PrintStream)
          at com.demo.guava.HardTask.call(HardTask.java:18)
          at com.demo.guava.HardTask.call(HardTask.java:9)
          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)
      
      "pool-1-thread-10" #19 prio=5 os_prio=0 tid=0x00007fc860345000 nid=0x45d7 waiting on condition [0x00007fc8418d3000]
      java.lang.Thread.State: WAITING (parking)
              at sun.misc.Unsafe.park(Native Method)
              - parking to wait for  <0x00000006c6c14178> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
              at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)

jmap

jmap命令是一个可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。

打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。

输出dump文件

-dump:[live,]format=b,file=

命令

jmap -dump:live,format=b,file=myjmapfile.txt 19570

结果

20210316192412

即可在/root目录打开myjmapfile.txt文件。

当然,file=后面也可以指定文件存放的目录,就可以在指定目录查看文件了。

打印等待回收对象的信息

命令:

jmap -finalizerinfo 3772

输出

20210316192502

结果:

Attaching to process ID 19570, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.80-b11
Number of objects pending for finalization: 0 (等候回收的对象为0个)

打印heap的概要信息

打印 GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况.

命令:

jmap -heap 19570

结果:

20210316192624

解析:

using parallel threads in the new generation.  ##新生代采用的是并行线程处理方式

using thread-local object allocation.   

Concurrent Mark-Sweep GC   ##同步并行垃圾回收

 

Heap Configuration:  ##堆配置情况,也就是JVM参数配置的结果[平常说的tomcat配置JVM参数,就是在配置这些]

   MinHeapFreeRatio = 40 ##最小堆使用比例

   MaxHeapFreeRatio = 70 ##最大堆可用比例

   MaxHeapSize      = 2147483648 (2048.0MB) ##最大堆空间大小

   NewSize          = 268435456 (256.0MB) ##新生代分配大小

   MaxNewSize       = 268435456 (256.0MB) ##最大可新生代分配大小

   OldSize          = 5439488 (5.1875MB) ##老年代大小

   NewRatio         = 2  ##新生代比例

   SurvivorRatio    = 8 ##新生代与suvivor的比例

   PermSize         = 134217728 (128.0MB) ##perm区 永久代大小

   MaxPermSize      = 134217728 (128.0MB) ##最大可分配perm区 也就是永久代大小


Heap Usage: ##堆使用情况【堆内存实际的使用情况】

New Generation (Eden + 1 Survivor Space):  ##新生代(伊甸区Eden区 + 幸存区survior(1+2)空间)

   capacity = 241631232 (230.4375MB)  ##伊甸区容量

   used     = 77776272 (74.17323303222656MB) ##已经使用大小

   free     = 163854960 (156.26426696777344MB) ##剩余容量

   32.188004570534986% used ##使用比例

Eden Space:  ##伊甸区

   capacity = 214827008 (204.875MB) ##伊甸区容量

   used     = 74442288 (70.99369812011719MB) ##伊甸区使用

   free     = 140384720 (133.8813018798828MB) ##伊甸区当前剩余容量

   34.65220164496263% used ##伊甸区使用情况

From Space: ##survior1区

   capacity = 26804224 (25.5625MB) ##survior1区容量

   used     = 3333984 (3.179534912109375MB) ##surviror1区已使用情况

   free     = 23470240 (22.382965087890625MB) ##surviror1区剩余容量

   12.43827838477995% used ##survior1区使用比例

To Space: ##survior2 区

   capacity = 26804224 (25.5625MB) ##survior2区容量

   used     = 0 (0.0MB) ##survior2区已使用情况

   free     = 26804224 (25.5625MB) ##survior2区剩余容量

   0.0% used ## survior2区使用比例

PS Old  Generation: ##老年代使用情况

   capacity = 1879048192 (1792.0MB) ##老年代容量

   used     = 30847928 (29.41887664794922MB) ##老年代已使用容量

   free     = 1848200264 (1762.5811233520508MB) ##老年代剩余容量

   1.6416783843721663% used ##老年代使用比例

Perm Generation: ##永久代使用情况

   capacity = 134217728 (128.0MB) ##perm区容量

   used     = 47303016 (45.111671447753906MB) ##perm区已使用容量

   free     = 86914712 (82.8883285522461MB) ##perm区剩余容量

   35.24349331855774% used ##perm区使用比例

打印每个class的实例数目,内存占用,类全名信息

-histo[:live],. 如果live子参数加上后,只统计活的对象数量.

命令

jmap -histo:live 19570

输出

num     #instances(实例)   #bytes(字节大小)  class name(类名)

----------------------------------------------

   1:         65220        9755240      <constMethodKlass>
   2:         65220        8880384      <methodKlass>
   3:         11721        8252112      [B
   4:          6300        6784040      <constantPoolKlass>
   5:         75224        6218208      [C
   6:         93969        5163280      <symbolKlass>
   7:          6300        4854440      <instanceKlassKlass>
   8:          5482        4203152      <constantPoolCacheKlass>
   9:         72097        2307104      java.lang.String
  10:         15102        2289912      [I
  11:          4089        2227728      <methodDataKlass>
  12:         28887        1386576      org.apache.velocity.runtime.parser.Token
  13:          6792         706368          java.lang.Class
  14:          7445         638312          [Ljava.util.HashMap$Entry;

...........

Total       1756265      162523736

采用jmap -histo pid>a.log日志将其保存,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。

jmap -dump:format=b,file=outfile 3024可以将3024进程的内存heap输出出来到outfile文件里,再配合MAT等分析工具

打印classload和jvm heap长久层的信息

-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来.

命令

jmap -permstat 19570

结果 20210316193422

其他

6> -F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效.

7> -h | -help 打印辅助信息

8> -J 传递参数给jmap启动的jvm.

其他
1
https://gitee.com/superwow/java-notes.git
git@gitee.com:superwow/java-notes.git
superwow
java-notes
java-notes
master

搜索帮助