[转帖]JVM性能调优监控工具

jvm,性能,监控,工具 · 浏览次数 : 0

小编点评

**CPU Usage Sampling Profiling** ```java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello ``` **CPU Usage Times Profiling** ```java -agentlib:hprof=cpu=times& javac -J-agentlib:hprof=cpu=times Hello.java ``` **Heap Allocation Profiling** ```java -J-agentlib:hprof=heap=sites Hello ``` **Heap Dump** ```java -J-agentlib:hprof=heap=dump Hello ``` **其他 JVM 性能调优参考资料** - 《Java虚拟机规范》 - 《Effective Java》VisualVM - 《Monitoring and Managing JavaSE 6 Applications》 - BTrace

正文

 

 
摘要: JDK自己提供了不少方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具,本博客但愿能起抛砖引玉之用,让你们能开始对JVM性能调优的经常使用工具备所了解。

    现实企业级Java开发中,有时候咱们会碰到下面这些问题:css

  • OutOfMemoryError,内存不足html

  • 内存泄露java

  • 线程死锁nginx

  • 锁争用(Lock Contention)程序员

  • Java进程消耗CPU太高算法

  • ......shell

    这些问题在平常开发中可能被不少人忽视(好比有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但可以理解并解决这些问题是Java程序员进阶的必备要求。本文将对一些经常使用的JVM性能调优监控工具进行介绍,但愿能起抛砖引玉之用。本文参考了网上不少资料,难以一一列举,在此对这些资料的做者表示感谢!关于JVM性能调优相关的资料,请参考文末。apache

 

A、 jps(Java Virtual Machine Process Status Tool)      ubuntu

    jps主要用来输出JVM中运行的进程状态信息。语法格式以下:数组

jps [options] [hostid]

    若是不指定hostid就默认为当前主机或服务器。

    命令行参数选项说明以下:

-q 不输出类名、Jar名和传入main方法的参数 -m 输出传入main方法的参数 -l 输出main类或Jar的全限名 -v 输出传入JVM的参数

   好比下面:

root@ubuntu:/# jps -m -l 2458 org.artifactory.standalone.main.Main /usr/local/artifactory-2.2.5/etc/jetty.xml 29920 com.sun.tools.hat.Main -port 9998 /tmp/dump.dat 3149 org.apache.catalina.startup.Bootstrap start 30972 sun.tools.jps.Jps -m -l 8247 org.apache.catalina.startup.Bootstrap start 25687 com.sun.tools.hat.Main -port 9999 dump.dat 21711 mrf-center.jar

 

B、 jstack

    jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式以下:

jstack [option] pid jstack [option] executable core jstack [option] [server-id@]remote-hostname-or-ip

    命令行参数选项说明以下:

-l long listings,会打印出额外的锁信息,在发生死锁时能够用jstack -l pid来观察锁持有状况 -m mixed mode,不只会输出Java堆栈信息,还会输出C/C++堆栈信息(好比Native方法)

    jstack能够定位到线程堆栈,根据堆栈信息咱们能够定位到具体代码,因此它在JVM性能调优中使用得很是多。下面咱们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。

    第一步先找出Java进程ID,我部署在服务器上的Java应用名称为mrf-center:

root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep root     21711     1  14:47 pts/3    00:02:10 java -jar mrf-center.jar

    获得进程ID为21711,第二步找出该进程内最耗费CPU的线程,可使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我这里用第三个,输出以下:

    TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为21742的线程,用

printf "%x\n" 21742

    获得21742的十六进制值为54ee,下面会用到。    

    OK,下一步终于轮到jstack上场了,它用来输出进程21711的堆栈信息,而后根据线程ID的十六进制值grep,以下:

root@ubuntu:/# jstack 21711 | grep 54ee "PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait() [0x00007f94c6eda000]

    能够看到CPU消耗在PollIntervalRetrySchedulerThread这个类的Object.wait(),我找了下个人代码,定位到下面的代码:

// Idle wait getLog().info("Thread [" + getName() + "] is idle waiting..."); schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting; long now = System.currentTimeMillis(); long waitTime = now + getIdleWaitTime(); long timeUntilContinue = waitTime - now; synchronized(sigLock) { try {      if(!halted.get()) {      sigLock.wait(timeUntilContinue);      }     }  catch (InterruptedException ignore) {     } }

    它是轮询任务的空闲等待代码,上面的sigLock.wait(timeUntilContinue)就对应了前面的Object.wait()。

 

C、 jmap(Memory Map)和jhat(Java Heap Analysis Tool)

    jmap用来查看堆内存使用情况,通常结合jhat使用。

    jmap语法格式以下:

jmap [option] pid jmap [option] executable core jmap [option] [server-id@]remote-hostname-or-ip

    若是运行在64位JVM上,可能须要指定-J-d64命令选项参数。

jmap -permstat pid

    打印进程的类加载器和类加载器加载的持久代对象信息,输出:类加载器名称、对象是否存活(不可靠)、对象地址、父类加载器、已加载的类大小等信息,以下图:

   使用jmap -heap pid查看进程堆内存使用状况,包括使用的GC算法、堆配置参数和各代中堆内存使用状况。好比下面的例子:

root@ubuntu:/# jmap -heap 21711 Attaching to process ID 21711, please wait... Debugger attached successfully. Server compiler detected. JVM version is 20.10-b01 using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration:    MinHeapFreeRatio = 40    MaxHeapFreeRatio = 70    MaxHeapSize      = 2067791872 (1972.0MB)    NewSize          = 1310720 (1.25MB)    MaxNewSize       = 17592186044415 MB    OldSize          = 5439488 (5.1875MB)    NewRatio         = 2    SurvivorRatio    = 8    PermSize         = 21757952 (20.75MB)    MaxPermSize      = 85983232 (82.0MB) Heap Usage: PS Young Generation Eden Space:    capacity = 6422528 (6.125MB)    used     = 5445552 (5.1932830810546875MB)    free     = 976976 (0.9317169189453125MB)    84.78829520089286% used From Space:    capacity = 131072 (0.125MB)    used     = 98304 (0.09375MB)    free     = 32768 (0.03125MB)    75.0% used To Space:    capacity = 131072 (0.125MB)    used     = 0 (0.0MB)    free     = 131072 (0.125MB)    0.0% used PS Old Generation    capacity = 35258368 (33.625MB)    used     = 4119544 (3.9287033081054688MB)    free     = 31138824 (29.69629669189453MB)    11.683876009235595% used PS Perm Generation    capacity = 52428800 (50.0MB)    used     = 26075168 (24.867218017578125MB)    free     = 26353632 (25.132781982421875MB)    49.73443603515625% used    ....

    使用jmap -histo[:live] pid查看堆内存中的对象数目、大小统计直方图,若是带上live则只统计活对象,以下:

root@ubuntu:/# jmap -histo:live 21711 | more

 num     #instances         #bytes  class name ----------------------------------------------    1:         38445        5597736  <constMethodKlass>    2:         38445        5237288  <methodKlass>    3:          3500        3749504  <constantPoolKlass>    4:         60858        3242600  <symbolKlass>    5:          3500        2715264  <instanceKlassKlass>    6:          2796        2131424  <constantPoolCacheKlass>    7:          5543        1317400  [I    8:         13714        1010768  [C    9:          4752        1003344  [B   10:          1225         639656  <methodDataKlass>   11:         14194         454208  java.lang.String   12:          3809         396136  java.lang.Class   13:          4979         311952  [S   14:          5598         287064  [[I   15:          3028         266464  java.lang.reflect.Method   16:           280         163520  <objArrayKlassKlass>   17:          4355         139360  java.util.HashMap$Entry   18:          1869         138568  [Ljava.util.HashMap$Entry;   19:          2443          97720  java.util.LinkedHashMap$Entry   20:          2072          82880  java.lang.ref.SoftReference   21:          1807          71528  [Ljava.lang.Object;   22:          2206          70592  java.lang.ref.WeakReference   23:           934          52304  java.util.LinkedHashMap   24:           871          48776  java.beans.MethodDescriptor   25:          1442          46144  java.util.concurrent.ConcurrentHashMap$HashEntry   26:           804          38592  java.util.HashMap   27:           948          37920  java.util.concurrent.ConcurrentHashMap$Segment   28:          1621          35696  [Ljava.lang.Class;   29:          1313          34880  [Ljava.lang.String;   30:          1396          33504  java.util.LinkedList$Entry   31:           462          33264  java.lang.reflect.Field   32:          1024          32768  java.util.Hashtable$Entry   33:           948          31440  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;

    class name是对象类型,说明以下:

B  byte C  char D  double F  float I  int J  long Z  boolean [  数组,如[I表示int[] [L+类名 其余对象

    还有一个很经常使用的状况是:用jmap把进程内存使用状况dump到文件中,再用jhat分析查看。jmap进行dump命令格式以下:

jmap -dump:format=b,file=dumpFileName pid

    我同样地对上面进程ID为21711进行Dump:

root@ubuntu:/# jmap -dump:format=b,file=/tmp/dump.dat 21711      Dumping heap to /tmp/dump.dat ... Heap dump file created

   dump出来的文件能够用MAT、VisualVM等工具查看,这里用jhat查看:

root@ubuntu:/# jhat -port 9998 /tmp/dump.dat Reading from /tmp/dump.dat... Dump file created Tue Jan 28 17:46:14 CST 2014 Snapshot read, resolving... Resolving 132207 objects... Chasing references, expect 26 dots.......................... Eliminating duplicate references.......................... Snapshot resolved. Started HTTP server on port 9998 Server is ready.

     注意若是Dump文件太大,可能须要加上-J-Xmx512m这种参数指定最大堆内存,即jhat -J-Xmx512m -port 9998 /tmp/dump.dat。而后就能够在浏览器中输入主机地址:9998查看了:

    上面红线框出来的部分你们能够本身去摸索下,最后一项支持OQL(对象查询语言)。

 

D、jstat(JVM统计监测工具)

    语法格式以下:

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

    vmid是Java虚拟机ID,在Linux/Unix系统上通常就是进程ID。interval是采样时间间隔。count是采样数目。好比下面输出的是GC信息,采样时间间隔为250ms,采样数为4:

root@ubuntu:/# jstat -gc 21711 250 4  S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT    192.0  192.0   64.0   0.0    6144.0   1854.9   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649 192.0  192.0   64.0   0.0    6144.0   1972.2   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649 192.0  192.0   64.0   0.0    6144.0   1972.2   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649 192.0  192.0   64.0   0.0    6144.0   2109.7   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649

    要明白上面各列的意义,先看JVM堆内存布局:

    能够看出:

堆内存 = 年轻代 + 年老代 + 永久代
年轻代 = Eden区 + 两个Survivor区(From和To)

    如今来解释各列含义:

S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)
EC、EU:Eden区容量和使用量
OC、OU:年老代容量和使用量
PC、PU:永久代容量和使用量
YGC、YGT:年轻代GC次数和GC耗时
FGC、FGCT:Full GC次数和Full GC耗时
GCT:GC总耗时

 

E、hprof(Heap/CPU Profiling Tool)

    hprof可以展示CPU使用率,统计堆内存使用状况。

    语法格式以下:

java -agentlib:hprof[=options] ToBeProfiledClass java -Xrunprof[:options] ToBeProfiledClass javac -J-agentlib:hprof[=options] ToBeProfiledClass

    完整的命令选项以下:

Option Name and Value  Description                    Default
---------------------  -----------                    -------
heap=dump|sites|all    heap profiling                 all
cpu=samples|times|old  CPU usage                      off
monitor=y|n            monitor contention             n
format=a|b             text(txt) or binary output     a
file=<file>            write data to file             java.hprof[.txt]
net=<host>:<port>      send data over a socket        off
depth=<size>           stack trace depth              4
interval=<ms>          sample interval in ms          10
cutoff=<value>         output cutoff point            0.0001
lineno=y|n             line number in traces?         y
thread=y|n             thread in traces?              n
doe=y|n                dump on exit?                  y
msa=y|n                Solaris micro state accounting n
force=y|n              force output to <file>         y
verbose=y|n            print messages about dumps     y

    来几个官方指南上的实例。

    CPU Usage Sampling Profiling(cpu=samples)的例子:

java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello

    上面每隔20毫秒采样CPU消耗信息,堆栈深度为3,生成的profile文件名称是java.hprof.txt,在当前目录。 

    CPU Usage Times Profiling(cpu=times)的例子,它相对于CPU Usage Sampling Profile可以得到更加细粒度的CPU消耗信息,可以细到每一个方法调用的开始和结束,它的实现使用了字节码注入技术(BCI):

javac -J-agentlib:hprof=cpu=times Hello.java

    Heap Allocation Profiling(heap=sites)的例子:

javac -J-agentlib:hprof=heap=sites Hello.java

    Heap Dump(heap=dump)的例子,它比上面的Heap Allocation Profiling能生成更详细的Heap Dump信息:

javac -J-agentlib:hprof=heap=dump Hello.java

    虽然在JVM启动参数中加入-Xrunprof:heap=sites参数能够生成CPU/Heap Profile文件,但对JVM性能影响很是大,不建议在线上服务器环境使用。

 

其余JVM性能调优参考资料:

《Java虚拟机规范》

《Java Performance》

《Trouble Shooting Guide for JavaSE 6 with HotSpot VM》: http://www.oracle.com/technetwork/java/javase/tsg-vm-149989.pdf 

《Effective Java》

VisualVM: http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/

jConsole: http://docs.oracle.com/javase/1.5.0/docs/guide/management/jconsole.html

Monitoring and Managing JavaSE 6 Applications: http://www.oracle.com/technetwork/articles/javase/monitoring-141801.html

BTrace:https://kenai.com/projects/btrace

与[转帖]JVM性能调优监控工具相似的内容:

[转帖]JVM性能调优监控工具

原文 https://www.cnblogs.com/haiyang1985/p/7654654.html 摘要: JDK自己提供了不少方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具,本

[转帖]JVM常用命令和性能调优建议 [Could not create the Java virtual machine]

https://blog.51cto.com/u_6215974/4938440 一、查看jvm常用命令 jinfo:可以输出并修改运行时的java 进程的opts。 jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。 jstat:一

[转帖]第七篇:双管齐下,JVM内部优化与JVM性能调优

文章目录 一、前言二、编译时优化2.1 Javac编译器2.2 Java语法糖2.2.1 泛型和泛型擦除2.2.2 自动装箱、自动拆箱、遍历循环2.2.3 条件编译 三、运行时优化(核心:JIT编译器/即时编译器)3.1 HotSpot虚拟机内的JIT编译器3.1.1 编译器和解释器并存的架构3.1

[转帖]JVM系列之:GC调优基础以及初识jstat命令

本文为《深入学习 JVM 系列》第二十二篇文章 影响垃圾收集性能有三个主要的属性,垃圾收集调优又有三个基本原则,以及垃圾收集调优时需要采集的信息。如果想要对垃圾收集进行调优,则需要根据实际场景对不同属性做出取舍,理解调优的原则以及收集什么信息。 性能属性 吞吐量 吞吐量是评价垃圾收集器能力的重要指标

[转帖]JVM 调优之 Reserved Code Cache Size

https://www.modb.pro/db/251381 01 现象 社区小伙伴最近在为 Kylin 4 开发 Soft Affinity + Local Cache 的性能测试过程中,遇到了压测场景下查询响应时间不稳定问题, RT 随着时间变化较大,现象如下: 同样的 SQL (只是参数不同)

[转帖]JVM调优汇总(JDK1.8)

JVM调优汇总 1、根据实际情况选择合适垃圾收集器 堆内存4G一下可以用parallel,4-8G可以用ParNew + CMS,8G以上可以用G1,几百级以上用ZGC。 2、jvm参数的初始值和最大值设置一样,避免扩容时消耗性能。 ‐Xms3072M ‐Xmx3072M ‐XX:Metaspace

[转帖]「性能优化系列」Tomcat线程连接池参数优化和JVM参数调优

尤其是以下三个配置项:maxConnections、maxThreads、acceptCount。 1.4.1 Tomcat的高效配置 Tomcat的maxConnections、maxThreads、acceptCount三大配置,分别表示最大连接数,最大线程数、最大的等待数,可以通过applic

[转帖]小知识点 之 JVM -XX:MaxGCPauseMillis 与 -XX:GCTimeRatio

https://www.cnblogs.com/hellxz/p/14056403.html 写在前边 JVM调优更多是针对不同应用类型及目标进行的调整,往往有很大的实验成份,通过实验来针对当前应用设置相对合适的参数,提高应用程序的性能与稳定性 最近在复习JVM,Parallel Scavenage

[转帖]性能优化 YYDS - Brendan Gregg 与 Intel.com 的故事

https://www.modb.pro/db/421309 译者序 金庸笔下的《鹿鼎记》有: !! 平生不识陈近南,便称英雄也枉然 现代的认真搞技术的后端程序员,应该也有一句: !! 平生不识 Brendan Gregg,便呆 BAT 也 SoSo 从 2016 年开始,做一个 JVM 调优开始,

[转帖]JVM性能提升50%,聊一聊背后的秘密武器Alibaba Dragonwell

https://zhuanlan.zhihu.com/p/453437019 今年四月五日,阿里云开放了新一代ECS实例的邀测[1],Alibaba Dragonwell也在新ECS上进行了极致的优化。相比于之前的dragonwell_11.0.8.3版本,即将发布的dragonwell_11.0.