Java-JVM-监控诊断/性能调优工具

Java-JVM-监控诊断/性能调优工具

摘要

本文会记录一些本人用到的一些java排错或观察各项性能指标的工具,如jstack jmap greys jps jstat等,不断完善中。

jinfo

看进程的所有配置参数、启动参数等

jinfo pid

1 jstack

1.1 简介

jstack可以看JVM栈的一些日志,可以统计运行线程数、查看指定线程号的栈信息等。

具体来说,jstack可被用于生成JVM线程快照,一般称为thread dumpjavacore文件,线程快照就是当前JVM内每一个线程正在执行的方法堆栈的集合,主要用来定位线程出现长时间停顿的原因,如死锁、死循环、请求外部资源长时间等待等。

1.2 查看指定线程号的栈信息

  1. 用ps找到目标进程号,当然也可以通过top pid来找资源最多的进程。

    $ ps aux | grep name
    $ ps aux | grep slave
    root     23556  0.0  0.0 103236   868 pts/0    S+   20:59   0:00 grep slave
    root     29793  6.9 18.0 6721828 1430008 ?     Sl    2018 9054:36 /usr/local/jdk1.8.0_77/bin/java
    

    可见,目标进程号为 29793

  2. 找到消耗CPU最多的线程号

    $ top -Hp 29793
    top - 21:02:18 up 106 days,  6:46,  1 user,  load average: 0.00, 0.00, 0.00
    Tasks: 860 total,   0 running, 860 sleeping,   0 stopped,   0 zombie
    Cpu(s):  2.4%us,  1.0%sy,  0.0%ni, 95.7%id,  0.4%wa,  0.0%hi,  0.5%si,  0.0%st
    Mem:   7928044k total,  7154288k used,   773756k free,   268028k buffers
    Swap:  8060920k total,   533128k used,  7527792k free,  3544100k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    29930 root      20   0 6564m 1.4g 6908 S  65.3 18.0  87:13.91 java
    19455 root      20   0 6564m 1.4g 6908 S  0.3 18.0   3:26.83 java
    19496 root      20   0 6564m 1.4g 6908 S  0.3 18.0   2:55.17 java
    

    可见,上述进程中CPU利用率比较高的线程号为29930。

    也可以使用如下命令:

    ps -mp 2633 -o THREAD,tid,time | sort -rn
    ps p 3036 -L -o pcpu,pid,tid,time,tname,cmd
    
  3. 线程号十进制转十六进制

    $ printf "%x\n" 29930
    74ea
    
  4. jstack查看消耗CPU的信息:
    jstack 进程号 |grep 16进制线程号

    $ jstack 29793 |grep 74ea
    "metrics-meter-tick-thread-2" #86 daemon prio=5 os_prio=0 tid=0x00007f7d480b6000 nid=0x74ea waiting on condition [0x00007f7cff5ef000]
    

    结果说明:
    在这里插入图片描述

    1. 线程名称,如果程序中没有显示给线程命名则显示默认名称
    2. 线程序号,相当于程序所有线程的一个编号
    3. 线程优先级,java中线程的默认优先级为5
    4. 线程系统优先级
    5. 线程id
    6. 线程native id,在linux中对应线程的轻量级进程id,十六进制,通过该字段都与top命令中的线程号(十进制)对应起来。
    7. 线程动作描述
    8. 线程栈的起始地址
    9. 线程状态(RUNNABLE就绪或运行、WAITING等待被唤醒、BLOCKED等待竞争对象锁)
    10. 线程执行堆栈,具体到代码的行数
  5. 也可以使用以下命令看该线程后指定行数的堆栈信息
    jstack -l 进程号 | grep -A 20 16进制线程号

    $ jstack -l 29793 | grep -A 20 74ea
    
  6. 可以把结果输出到某个文件,然后在结果里面找刚才16进制线程号关键字

  7. 十六进制转10进制

    echo "5C3"|awk '{printf("%d\n",strtonum("0x"$1))}'  
    

还可参考:

1.3 查看线程个数

  1. 先通过top命令来查看出问题的进程
  2. 可通过jstat -gc pid 2000 来查看出问题的进程的GC情况
  3. 可通过jmap -dump:format=b,file=fileName PID进行dump保存堆现场
  4. 然后通过grep 'java.lang.Thread.State' jstack.log | wc -l来计算线程数
  5. grep -A 1 'java.lang.Thread.State' jstack.log | grep -v 'java.lang.Thread.State' | sort | uniq -c |sort -n 查看有无异常日志
  6. 可以用MAT分析dump文件,内存泄露一般会有很多对象的情况,找到他在代码中位置

2 greys

greys是一款Java在线问题诊断工具,主页greys-anatomy

2.1 安装

curl -sLk http://ompc.oss.aliyuncs.com/greys/install.sh|bash

命令将会下载的启动脚本文件greys.sh到当前目录,你可以放在任何地方或加入到$PATH中

2.2 使用

查看指定类的指定方法传入的参数情况,还可以加入任意字符串便于看懂输出:

watch -b com.chengc.test.Statistics testmethod "'<user_id,'+params[0]+'>'+'__<user_name,'+params[1]+'>'+'__<age,'+params[2]+'>'+'__<country,'+params[3]+'>'"

2.3 更多参考文档

Greys原理分析

Greys命令手册

Greys观察维度列表

3 jmap

3.1 简介

jmap可方便的查看jvm 堆统计、对象统计、dump等

3.2 命令基本格式

# 连接运行中的进程
jmap [option] <pid>
# to connect to a core file
jmap [option] <executable <core>
# 连接远程调试服务器
jmap [option] [server_id@]<remote server IP or hostname>

上面选项:

  • option:可选参数。注意不可同时使用多个选项参数
  • pid:进程号
  • executable:产生核心dump的java可执行文件
  • core:需要打印配置信息的核心文件
  • remote-hostname-or-ip:远程调试服务器的hostName/ip
  • server-id:可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器

3.3 option

上述的[option]有以下选项:

<none>               to print same info as Solaris pmap
-heap                打印java heap统计信息
-histo[:live]        打印java对象统计信息; 如果`:live`加了,就只统计存活对象
-clstats             打印classloader统计信息
-finalizerinfo       打印等待finalization的对象信息
-dump:<dump-options> 生成java heap dump文件
                     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

3.4 例子

3.4.1 逃逸分析

在逃逸分析时,可以使用jmap辅助查看逃逸分析的执行效果:
jmap逃逸分析

3.4.2 另一个histo例子
jmap -histo:live pid

jmap例子2
以上结果说明:

符号含义
Bbyte
Cchar
Ddouble
Ffloat
Iint
Jlong
Zboolean
[基本类型数组,如[I表示int[]
[L+类名自定义类数组
[类名自定义类对象
具体可见Java-JVM-逃逸分析

3.5 dump

可以使用以下命令对java进程进行dump操作:

jmap -dump:format=b,live,file=fileName PID

例如,我们这里对idea的进程的存活对象进行dump:

jmap -dump:format=b,live,file=jmap_idea_dump.tmp 34208

这样,在执行命令的目录下就生成了jmap_idea_dump.tmp

3.6 MAT分析dump文件

可在http://www.eclipse.org/mat/downloads.php下载

分析可参考:

3.6.1 使用MAT(memory anaylyzer tool)打开这个文件

MAT
可以看到 深色部分的内存被怀疑内存泄露。下面的Problem Suspect1就是问题怀疑的描述,说io.netty.buffer.PoolChunk占用了81.36%

3.6.2 Shallow SizeRetained Size
  • Shallow Size
    是对象本身占据的内存的大小,不包含其他引用的其他对象。对于常规对象(非数组)的Shallow Size由其成员变量的数量和类型来定。

    数组的ShallowSize由数组类型和数组长度来决定,它为数组元素大小的总和。

  • Retained Size
    对象本身加上可直接或间接引用(A->B->C,C就是A的间接引用)到的对象的大小,然后减去被GC Roots存在另外一条路径引用的对象,也就是说是该对象自己引用但并没有被GC Roots直接或间接引用的路径(这个路径不包含目标对象)。

    所以这也可以理解为GC之后所能回收到内存的总和,因为回收目标对象也能回收这种类型的引用对象。

更多可看这两篇译文:
https://www.yourkit.com/docs/java/help/sizes.jsp 或这篇译文 http://blog.csdn.net/kingzone_2008/article/details/9083327 讲的很详细

3.6.3 Histogram

Histogram
Retained为一次FullGC后的还存活的大小

3.6.4 Dominator Tree(支配树)

首先说下Dominator和持有的区别:

  • 持有就是我们一般讲的该对象持有另一个对象的引用。
  • Dominator的意思不局限于直接持有或间接持有,而是突出一种唯一性的特点。比如A支配B,表示要经过B的引用路径里必须经过A,则认为对象A为对象B的直接支配。

关于Dominator Tree的概念以下这篇文章会讲的很详细支配树(Dominator Tree)

引用树(右)和支配树(左)关系如下:
引用树和支配树

对象A和B由根对象直接支配,由于在到对象C的路径中,可以经过A,也可以经过B,因此对象C的直接支配者也是根对象。

下面看看MAT中的dominator_tree
Dominator Tree
Dominator Tree,中文翻译为支配(对象)树?所以点击每一行左边的箭头会列举出这个对象所支配的所有对象。
Dominator Tree2
注意是支配(对象),而不是用持有(对象)树。

3.6.5 List Object

前面展示的每一行都能点右键,然后选择 List Object
List Object

  • with outgoing references
    可以列出这个对象里所持有的所有对象们。
  • with incoming references
    可以列出所有持有这个对象的对象们。
3.6.6 Path To GC Roots

Path To GC Roots是针对Dominator Tree表格的,在任一行上点右键可看到该菜单项。在Histogram里只有Merge shortest Path To GC Roots,意思是会找出最短的路径。

Path To GC Roots人如其名,意为显示出GC Roots到这个对象的所有路径。一般用exclude all phantom/weak/soft etc. references这个排除虚、弱、软引用的这个选项。因为这几种情况堆内存GC都可以回收的到,不是造成内存泄漏的原因。唯有强引用指向的对象GC回收不了。选中后出现如下图表格:
Path To GC Roots
这图很直白。DemoActivity对象 ←(被持有) MySingleton对象的mContext引用 ←(被持有) MySingleton对象的instance引用(因为是静态变量,GC不会回收)。

3.7 jmap -heap

可以看java应用heap配置的分配情况以及使用情况。

jmap -heap 35132

jmap

4 jconsole

可参考JConsole&VisualVM监控总结

4.1 简介

图形化的JVM分析工具。安装jdk后自带,比如我的mac下jconsole位于

/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/jconsole

4.2 使用

命令行终端直接敲jconsole进入jconsole:
jconsole

这里我们选择一个本地idea进程,然后点连接,进入界面:

  • 概览界面可以看到堆内存、线程、加载类、CPU情况
    jconsole
  • 内存界面堆内(各个划分区)、堆外内存、元空间、CodeCache(存放JIT编译字节码为机器码)、CompressedClassSpace等的使用情况:
    jconsole 内存
    还可以看看该进程的JVM概要情况:
    JVM概要

5 jps

5.1 简介

jps 命令可查看 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息。

5.2 命令基本格式

$ jps -help
usage: jps [-help]
       jps [-q] [-mlvV] [<hostid>]

Definitions:
    <hostid>:      <hostname>[:<port>]

5.3 使用

  • jps不带参数
    不带参数时,就是展示所有正在运行的java应用
  • -q
    只打印进程的ID号
  • -m
    打印传入 main 方法的参数
    jps-m
  • -l:打印完整包名、应用主类名或jar的完全路径名
  • -v:输出JVM启动参数
  • -V:输出通过flag文件传递到JVM中的参数
  • [hostid]:远程服务器host
  • [protocol:][[//]hostname][:port][/servername]
    具体远程连接方法参考jvm 性能调优工具之 jps

6 jstat

6.1 基本语法

jstat [-options] pid interval

options如下:

  • class 查看类加载信息
  • compile 编译统计信息
  • gc 垃圾回收信息
  • gcXXX 各区域 GC 的详细信息,如 -gcold,- gcutil

在这里插入图片描述
使用-gccause时,LGCC表示上次gc的原因,GCC表示此次gc的原因。注意:当使用CMS作为老年代收集器的时候,每执行一次Old GC,FGC就会增加两次。

6.2 简介

使用jstat java gc情况

  • 内存使用百分比
jstat -gcutil pid 间隔时间(毫秒)

jstat例子1

  • 以上各列含义:
名称含义
S0年轻代幸存者0区使用百分比
S1年轻代幸存者1区使用百分比
E年轻代Eden区使用百分比
O老年代使用百分比
M元空间使用百分比
CCSCompressedClassSpaceSize使用百分比
YGC从应用程序启动到当前采样时,YoungGC次数
YGCT从应用程序启动到采样时YongGC总耗时(s)
FGC从应用程序启动到当前采样时,FullGC次数
FGCT从应用程序启动到采样时FullGC总耗时(s)
GCT从应用程序启动到采样时GC总耗时
  • 内存使用详情
jstat -gc pid 间隔时间(毫秒)

jstat例子2
以上数据单位为KB。可以配合使用jmap进行查看:
jmap

6.3 示例

小心踩雷,一次Java内存泄漏排查实战

7 jhat

7.1 简介

jhat为jdk自带,可以配合jmap分析其dump出的文件,且以html方式输出结果,包括对象的数量,大小等等,并支持对象查询语言OQL。

7.2 jmap dump

  • dump命令格式
jmap -dump:format=b,file=dumpFileName pid
  • 实例
$ jmap -dump:format=b,file=/Users/chengc/cc/dumptest.dat 41005
Dumping heap to /Users/chengc/cc/dumptest.dat ...
Heap dump file created

7.3 jhat 分析dump

$ jhat /Users/chengc/cc/dumptest.dat
Reading from /Users/chengc/cc/dumptest.dat...
Dump file created Sat Feb 16 17:59:22 CST 2019
Snapshot read, resolving...
Resolving 89501 objects...
Chasing references, expect 17 dots.................
Eliminating duplicate references.................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

如果目标dump文件太大,可以加以下参数限制内存:

-J<flag>          Pass <flag> directly to the runtime system. For
			  example, -J-mx512m to use a maximum heap size of 512MB

7.4 访问该分析服务

jhat结果

8 jprofile

8.1 简介

需要收费。wat

JProfiler是由ej-technologies GmbH公司开发的一款性能瓶颈分析工具(该公司还开发部署工具),专用于分析J2SE和J2EE应用。JProfiler的GUI可以更方便地找到性能瓶颈、抓住内存泄漏(memory leaks),并解决多线程的问题,例如分析哪个对象占用的内存比较多、哪个方法占用较大的CPU资源等。可使用Jprofiler来监控Spark应用在local模式下运行时的性能瓶颈和内存泄漏情况。
其特点:

  • 使用方便
  • 界面操作友好
  • 对被分析的应用影响小
  • CPU,Thread,Memory分析功能尤其强大
  • 支持对jdbc,noSql, jsp, servlet, socket等进行分析
  • 支持多种模式(离线,在线)的分析
  • 跨平台

8.2 jprofile参考

Java性能分析神器-JProfiler详解

Intellij IDEA集成JProfiler性能分析神器

使用JProfiler进行内存分析

生产环境-jvm内存溢出-jprofile问题排查

eveloper.aliyun.com/article/1084285)

9 javap

javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码指令,并且贴心的附上了注释。

用法很简单,只需要对编译后的TestClass.class文件输入以下命令:

javap -c TestClass

具体可以参考例子javap的基本用法

10 JVisualVM

可参考

10.1 概述

JVisualVM可
本地命令行直接通过JVisualVM就可启动。

可观察Java程序资源使用情况,可方便地进行堆/内存 dump等。

VisualVmM是强大的运行监视和故障处理数据,他不需要被监视的目标程序基于特殊的agent运行,因此它对应用程序地实际性能影响很小,使得它可以直接应用到生产环境中。它上面有许多好玩的插件,比如Btrace,它可是线上调试的神奇,可以在不停止目标程序运行的前提下,通过hotspot的hotswap技术动态加入原本不存在的调试代码。

10.2 分析dump文件

查看对象个数等

10.3 分析hprof文件

在这里插入图片描述

11 Btrace

btrace有诸多安全限制,需要增加jvm启动参数-Dcom.sun.btrace.unsafe=true,并且需要编写代码。

12 阿里-Arthas

12.1 概念

Arthas类似linux shell,直接敲命令解决所有问题,好用太多

可参考:

12.2 下载安装和启动

  • 下载
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
  • 启动arthas shell
java -jar arthas-boot.jar
  • 选择应用java进程:
    输入根据提示的进程对应的编号,然后回车绑定
  • help
    进入命令行后,可以输入help看有哪些命令

12.3 watch例子

查看一个say方法的传入参数,且是在抛异常后(-e),只捕获一条符合要求的(要求是第一个参数值为’tom’)。

watch com.chengc.Hello say {"params[0]","params[1]","params[1][0].keys","params[1][0].values",returnObj} "params[0]=='tom'" -x 2 -n 1 -e
  • say方法如下
    int say(String name, List<Map<String, Object>> records){
    	try{
    		...
    		return 0;
    	}catch(Exception e){
    		throw new RuntimeException("xxx")
    	}
    }
    

这个时候可以得到:

  • 第一个参数
  • 第二个参数描述(这里是ArrayList的元素和每个元素HashMap的描述)
  • 第二个参数首个Map的keys集且属性遍历深度为2(默认1就是描述对象本身,2时会描述内部对象,这里就是所有key)
  • 第二个参数首个Map的values集且属性遍历深度为2
  • 返回值(我们加了-e参数所以返回值肯定为null

12.4 注意事项

在这里插入图片描述

12.5 dashboard

命令行图形化

展示当前进程的信息,按ctrl+c可以中断执行。

12.6 jvm

12.7 thread

  • thread tid
    可打出调用栈信息
  • thread -help
    打出所有参数
  • thread -b
    找出持有让大多数线程等待的锁的线程对象
  • thread tid | grep ‘main(’
    at demo.MathGame.main(MathGame.java:17)

12.8 heapdump

导出堆内存快照

12.9 jad className

反编译类

可用来查线上代码版本是不是对的

12.10 redefine

救急用,线上热更新class

12.10 退出

如果只是退出当前的连接,可以用quit或者exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。

如果想完全退出arthas,可以执行stop命令。

12.11 arthas profiler 火焰图

13 GC可视化

可参考:

13.1 GCEasy

官网GCEasy

参考可视化GC分析工具

13.2 GCViewer

官网GCViewer

参考可视化GC分析工具

13.3 Visual GC

JVisualVM 工具的 “VisualGC” 插件提供了基本的 JMX客户端功能, 还实时显示出 GC事件以及各个内存空间的使用情况。
参考 GC 调优(工具篇) - GC参考手册

14 Jmeter

jmeter是apache公司基于java开发的一款开源压力测试工具,体积小,功能全,使用方便,是一个比较轻量级的测试工具,使用起来非常简单。

因为jmeter是java开发的,所以运行的时候必须先要安装jdk。

jmeter本身是免安装的,直接解压安装包就可以使用,适用于linux/windows/macos。

参考:

15 Hprof

15.1 简介

Hprof和Jmap一样可以统计堆内存使用情况、Dump等,但他还能能够展现CPU使用率。

可参考:

15.2 语法

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

15.3 使用

15.3.1 Dump
  • 开启Hprof Dump
    在启动Java程序时,在JVM配置中加上-XX:+HeapDumpOnOutOfMemoryError ,表示在内存出现OOM的时候,把Heap转存(Dump)到磁盘文件以便后续分析。

    文件名通常是java_pid<pid>.hprof,其中pid为该应用的进程号。

    随后可以使用JHat或MAT或JVisualVM对,hprof文件进行分析。

  • Dump文件路径配置
    -XX:HeapDumpPath=<path>

    注意,该目录必须存在,否则出错!不设置时,如果运行tomcat则放在/tomcat_home/bin目录下。

tcpdump

切大流量到某个指定机器,用来测试大流量带来的问题。

注意事项

  • 线上不能使用jmap导出堆快照,否则造成线上业务暂停受较大影响。

  • 正确做法为在启动Java程序时,在JVM配置中加上-XX:+HeapDumpOnOutOfMemoryError ,表示在内存出现OOM的时候,把Heap转存(Dump)到磁盘文件以便后续分析。

    文件名通常是java_pid<pid>.hprof,其中pid为该应用的进程号。

    随后可以使用JHat或MAT对,hprof文件进行分析。

    • Dump文件路径配置
      -XX:HeapDumpPath=<path>

      注意,该目录必须存在,否则出错!不设置时,如果运行tomcat则放在/tomcat_home/bin目录下。

实例

0xFF 参考文档

1 更多文章

GC日志分析工具

一份详尽的 Java 问题排查工具清单

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat等使用详解

JVM 图形化监控工具

Eclipse Memory Analyzer tool 工具的使用

Memory Analyzer Tool 使用手记

MAT(Memory Analyzer Tool)使用心得

2 参考文档

JVM调优命令-jmap

Java8 Non-Heap 中的metaspace 和compressed class space解释

jvm 性能调优工具之 jps

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解

内存泄漏检测分析工具MAT(Memory Analyzer Tool)的使用

支配树(Dominator Tree)

Java性能分析神器-JProfiler详解

小心踩雷,一次Java内存泄漏排查实战

jstack分析线程快照的三步曲及CPU占用过高和死锁问题的排查

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值