JVM相关工具

3. JVM相关工具

3.1 JDK工具包

3.1.1 jps

jps:Java Virtual Machine Process Status Tool

查看Java进程 ,相当于Linux下的ps命令,只不过它只列出Java进程。

jps :列出Java程序进程ID和Main函数名称
jps -q :只输出进程ID
jps -m :输出传递给Java进程(主函数)的参数
jps -l :输出主函数的完整路径
jps -v :显示传递给Java虚拟的参数
3.1.2 jstat

jstat:JVM Statistics Monitoring Tool

jstat可以查看Java程序运行时相关信息,可以通过它查看堆信息的相关情况

jstat - [-t] [-h]  [ []]
options:由以下值构成
-class:显示ClassLoader的相关信息
-compiler:显示JIT编译的相关信息
-gc:显示与GC相关信息
-gccapacity:显示各个代的容量和使用情况
-gccause:显示垃圾收集相关信息(同-gcutil),同时显示最后一次或当前正在发生的垃圾收集的诱发原因
-gcnew:显示新生代信息
-gcnewcapacity:显示新生代大小和使用情况
-gcold:显示老年代信息
-gcoldcapacity:显示老年代大小
-gcpermcapacity:显示永久代大小
-gcutil:显示垃圾收集信息

示例一:

下面输出的是GC信息,34784 是 进程ID ,采样时间间隔为250ms,采样数为4。

jstat -gc 30108 250 4
S0C:年轻代中第一个survivor(幸存区)的容量 (单位kb)
S1C:年轻代中第二个survivor(幸存区)的容量 (单位kb)
S0U :年轻代中第一个survivor(幸存区)目前已使用空间 (单位kb)
S1U :年轻代中第二个survivor(幸存区)目前已使用空间 (单位kb)
EC :年轻代中Eden(伊甸园)的容量 (单位kb)
EU :年轻代中Eden(伊甸园)目前已使用空间 (单位kb)
OC :Old代的容量 (单位kb)
OU :Old代目前已使用空间 (单位kb)
MC:metaspace(元空间)的容量 (单位kb)
MU:metaspace(元空间)目前已使用空间 (单位kb)
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC :从应用程序启动到采样时年轻代中gc次数
YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)
FGC :从应用程序启动到采样时old代(全gc)gc次数
FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)

示例二:

jstat -gcutil 30108 1s 5
# 1s每隔1秒采样一次
# 共采样五次
S0 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E 年轻代中Eden(伊甸园)已使用的占当前容量百分比
O old代已使用的占当前容量百分比
M metaspace已使用的占当前容量百分比
CCS 压缩使用比例
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
3.1.3 jinfo

jinfo:Java Configuration Info

jinfo可以用来查看正在运行的java程序的扩展参数,甚至支持运行时,修改部分参数

jinfo [option] 
-flags 打印虚拟机 VM 参数 
-flag <name> 打印指定虚拟机 VM 参数 
-flag [+|-]<name> 打开或关闭虚拟机参数
-flag <name>=<value> 设置指定虚拟机参数的值

示例:

jinfo -flags 30108
3.1.4 jmap

jmap:Memory Map

jmap用来查看堆内存使用状况,一般结合jhat使用。

jmap语法格式如下:

Usage:
    jmap [option] 
        (to connect to running process)
    jmap [option] 
        (to connect to a core file)
    jmap [option] [server_id@]
        (to connect to remote debug server)

where 

参数:

option: 选项参数。
pid: 需要打印配置信息的进程ID。
executable: 产生核心dump的Java可执行文件。
core: 需要打印配置信息的核心文件。
server-id: 可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器。
remote server IP or hostname 远程调试服务器的IP地址或主机名。

option
no option: 查看进程的内存映像信息,类似 Solaris pmap 命令。
heap: 显示Java堆详细信息
histo[:live]: 显示堆中对象的统计信息
clstats:打印类加载器信息
finalizerinfo: 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
dump::生成堆转储快照
F: 当-dump没有响应时,使用-dump或者-histo参数. 在这个模式下,live子参数无效.
help:打印帮助信息
J:指定传递给运行jmap的JVM的参数

示例一:no option

命令:jmap pid
描述:查看进程的内存映像信息,类似 Solaris pmap 命令。

使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。这与Solaris的pmap工具比较相似。

jmap 30108

示例二:heap

命令:jmap -heap pid
描述:显示Java堆详细信息

打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息

示例三:histo[:live]

命令:jmap -histo:live pid
描述:显示堆中对象的统计信息

其中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。打印的虚拟机内部的类名称将会带有一个’*’前缀。如果ja指定了live子选项,则只计算活动的对象。

示例四:clstats
命令:jmap -clstats pid
描述:打印类加载器信息

-clstats是-permstat的替代方案,在JDK8之前,-permstat用来打印类加载器的数据
打印Java堆内存的永久保存区域的类加载器的智能统计信息。对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印。

示例五:finalizerinfo
命令:jmap -finalizerinfo pid
描述:打印等待终结的对象信息

Number of objects pending for finalization: 0 说明当前F-QUEUE队列中并没有等待Fializer线程执行final

示例六:dump:
命令:jmap -dump:format=b,file=heapdump.hprof pid
描述:生成堆转储快照dump文件。

以hprof二进制格式转储Java堆到指定filename的文件中。live子选项是可选的。如果指定了live子选项,堆中只有活动的对象会被转储。想要浏览heap dump,你可以使用jhat(Java堆分析工具)读取生成的文件。

这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用, 线上系统慎用。

3.1.5 jhat

jhat:Java Heap Analysis Tool,jhat 命令解析Java堆转储文件,并启动一个 web server. 然后用浏览器来查看/浏览 dump 出来的 heap. jhat 命令支持预先设计的查询, 比如显示某个类的所有实例. 还支持 对象查询语言(OQL, Object Query Language)。 OQL有点类似SQL,专门用来查询堆转储。 OQL相关的帮助信息可以在 jhat 命令所提供的服务器页面最底部. 如果使用默认端口, 则OQL帮助信息页面为: http://localhost:7000/oqlhelp/

Java生成堆转储的方式有多种:

  • 使用 jmap -dump 选项可以在JVM运行时获取 heap dump.
  • 使用 jconsole 选项通过 HotSpotDiagnosticMXBean 从运行时获得堆转储。
  • 在虚拟机启动时如果指定了 -XX:+HeapDumpOnOutOfMemoryError 选项, 则抛出 OutOfMemoryError 时, 会自动执行堆转储。
  • 使用 hprof 命令。
jhat [ options ] heap-dump-file

参数:

  • options 可选命令行参数,请参考下面的 Options
  • heap-dump-file 要查看的二进制Java堆转储文件(Java binary heap dump file)。 如果某个转储文件中包含了多份 heap dumps, 可在文件名之后加上 # 的方式指定解析哪一个 dump, 如: myfile.hprof#3

Options

-stack false|true

关闭对象分配调用栈跟踪(tracking object allocation call stack)。 如果分配位置信息在堆转储中不可用. 则必须将此标志设置为 false. 默认值为 true.

-refs false|true

关闭对象引用跟踪(tracking of references to objects)。 默认值为 true. 默认情况下, 返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references), 会统计/计算堆中的所有对象。

-port port-number

设置 jhat HTTP server 的端口号. 默认值 7000.

-exclude exclude-file

指定对象查询时需要排除的数据成员列表文件(a file that lists data members that should be excluded from the reachable objects query)。 例如, 如果文件列列出了 java.lang.String.value , 那么当从某个特定对象 Object o 计算可达的对象列表时, 引用路径涉及 java.lang.String.value 的都会被排除。

-baseline exclude-file

指定一个基准堆转储(baseline heap dump)。 在两个 heap dumps 中有相同 object ID 的对象会被标记为不是新的(marked as not being new). 其他对象被标记为新的(new). 在比较两个不同的堆转储时很有用.

-debug int

设置 debug 级别. 0 表示不输出调试信息。 值越大则表示输出更详细的 debug 信息.

-version

启动后只显示版本信息就退出

-h

显示帮助信息并退出. 同 -help

-help

显示帮助信息并退出. 同 -h

-J< flag >

因为 jhat 命令实际上会启动一个JVM来执行, 通过 -J 可以在启动JVM时传入一些启动参数. 例如, -J-Xmx512m 则指定运行 jhat 的Java虚拟机使用的最大堆内存为 512 MB. 如果需要使用多个JVM启动参数,则传入多个 -Jxxxxxx.

示例一:

利用jhat分析刚刚jmap输出的堆文件:

这样就启动起来了一个简易的HTTP服务,端口号是7000,尝试一下用浏览器访问一下它,本地的可以通过http://localhost:7000就可以得到这样的页面:

jhat 启动后显示的 html 页面中包含有:

  • All classes including platform:显示出堆中所包含的所有的类
  • Show all members of the rootset :从根集能引用到的对象
  • Show instance counts for all classes (including platform/excluding platform):显示平台包括的所有类的实例数量
  • Show heap histogram:堆实例的分布表
  • Show finalizer summary:Finalizer 摘要
  • Execute Object Query Language (OQL) query:执行对象查询语句(OQL)
3.1.6 jstack

jstack:Java Stack Trace,jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

在thread dump中,要留意下面几种状态

  • 死锁,Deadlock(重点关注)
  • 等待资源,Waiting on condition(重点关注)
  • 等待获取监视器,Waiting on monitor entry(重点关注)
  • 阻塞,Blocked(重点关注)
  • 执行中,Runnable
  • 暂停,Suspended
  • 对象等待中,Object.wait() 或 TIMED_WAITING
  • 停止,Parked

使用方式

jstack [ option ] pid 查看当前时间点,指定进程的dump堆栈信息。
jstack [ option ] pid > 文件 将当前时间点的指定进程的dump堆栈信息,写入到指定文件中。	注:若该文件不存在,则会自动生成;若该文件存在,则会覆盖源文件。
jstack [ option ] executable core 查看当前时间点,core文件的dump堆栈信息。
jstack [ option ] [server_id@]  查看当前时间点,远程机器的dump堆栈信息。

可选参数说明

-F 当进程挂起了,此时'jstack [-l] pid'是没有相应的,这时候可使用此参数来强制打印堆栈信息,强制jstack),一般情况不需要使用。
-m 打印java和native c/c++框架的所有栈信息。可以打印JVM的堆栈,以及Native的栈帧,一般应用排查不需要使用。
-l 长列表. 打印关于锁的附加信息。例如属于java.util.concurrent的ownable synchronizers列表,会使得JVM停顿得长久得多(可能会差很多倍,比如普通的jstack可能几毫秒和一次GC没区别,加了-l 就是近一秒的时间),-l 建议不要用。一般情况不需要使用。
-h or -hel 打印帮助信息

示例一:

将指定进程的当前堆栈情况记录到某个文件中:

示例二:

统计线程数

jstack -l 30108 | grep 'java.lang.Thread.State' | wc -l
3.1.7 VisualVM

开发大型 Java 应用程序的过程中难免遇到内存泄露、性能瓶颈等问题,比如文件、网络、数据库的连接未释放,未优化的算法等。随着应用程序的持续运行,可能会造成整个系统运行效率下降,严重的则会造成系统崩溃。为了找出程序中隐藏的这些问题,在项目开发后期往往会使用性能分析工具来对应用程序的性能进行分析和优化。

VisualVM 是一款免费的性能分析工具。它通过 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多种方式从程序运行时获得实时数据,从而进行动态的性能分析。同时,它能自动选择更快更轻量级的技术尽量减少性能分析对应用程序造成的影响,提高性能分析的精度。

性能分析的主要方式

1)监视:

监视是一种用来查看应用程序运行时行为的一般方法。通常会有多个视图(View)分别实时地显示 CPU 使用情况、内存使用情况、线程状态以及其他一些有用的信息,以便用户能很快地发现问题的关键所在。

2)转储:

性能分析工具从内存中获得当前状态数据并存储到文件用于静态的性能分析。Java 程序是通过在启动 Java 程序时添加适当的条件参数来触发转储操作的。它包括以下三种:

  • 系统转储:JVM 生成的本地系统的转储,又称作核心转储。一般的,系统转储数据量大,需要平台相关的工具去分析,如 Windows 上的 windbg 和 Linux 上的 gdb。

  • Java 转储:JVM 内部生成的格式化后的数据,包括线程信息,类的加载信息以及堆的统计数据。通常也用于检测死锁。

  • 堆转储:JVM 将所有对象的堆内容存储到文件。

3)快照:

应用程序启动后,性能分析工具开始收集各种运行时数据,其中一些数据直接显示在监视视图中,而另外大部分数据被保存在内部,直到用户要求获取快照,基于这些保存的数据的统计信息才被显示出来。快照包含了应用程序在一段时间内的执行信息,通常有 CPU 快照和内存快照两种类型。

  • CPU 快照:主要包含了应用程序中函数的调用关系及运行时间,这些信息通常可以在 CPU 快照视图中进行查看。

  • 内存快照:主要包含了内存的分配和使用情况、载入的所有类、存在的对象信息及对象间的引用关系等。这些信息通常可以在内存快照视图中进行查看。

4)性能分析:

性能分析是通过收集程序运行时的执行数据来帮助开发人员定位程序需要被优化的部分,从而提高程序的运行速度或是内存使用效率,主要有以下三个方面:

  • CPU 性能分析:CPU 性能分析的主要目的是统计函数的调用情况及执行时间,或者更简单的情况就是统计应用程序的 CPU 使用情况。通常有 CPU 监视和 CPU 快照两种方式来显示 CPU 性能分析结果。

  • 内存性能分析:内存性能分析的主要目的是通过统计内存使用情况检测可能存在的内存泄露问题及确定优化内存使用的方向。通常有内存监视和内存快照两种方式来显示内存性能分析结果。

  • 线程性能分析:线程性能分析主要用于在多线程应用程序中确定内存的问题所在。一般包括线程的状态变化情况,死锁情况和某个线程在线程生命期内状态的分布情况等

远程可视化监控JVM

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Djava.rmi.server.hostname=172.26.233.198 
-Dcom.sun.management.jmxremote.rmi.port=9999

#JAVA_OPT="${JAVA_OPT} -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=172.26.233.198 -Dcom.sun.management.jmxremote.rmi.port=9999"

3.2 第三方工具

3.2.1 GCEasy

https://gceasy.io/

业界首先采用机器学习算法解决GC日志分析问题,GCeasy内置机器智能可以自动检测JVM和Android GC日志中的问题,并推荐解决方案。

GC日志分析是免费的,Machine Learning收费

  • 几秒内解决GC和内存问题
  • JVM堆优化建议
  • 机器学习算法
3.2.2 MAT
1)介绍

MAT是一个强大的内存分析工具,可以快捷、有效地帮助我们找到内存泄露,减少内存消耗分析工具。MAT是Memory Analyzer tool的缩写,是一种快速,功能丰富的Java堆分析工具,能帮助你查找内存泄漏和减少内存消耗。很多情况下,我们需要处理测试提供的hprof文件,分析内存相关问题,那么MAT也绝对是不二之选。

使用MAT,可以轻松实现以下功能:

  • 找到最大的对象,因为MAT提供显示合理的累积大小(retained size)

  • 探索对象图,包括inbound和outbound引用,即引用此对象的和此对象引出的

  • 查找无法回收的对象,可以计算从垃圾收集器根到相关对象的路径

  • 找到内存浪费,比如冗余的String对象,空集合对象。

2)安装

MAT安装有两种方式,一种是以eclipse插件方式安装,一种是独立安装。在MAT的官方文档中有相应的安装文件下载,下载地址为:https://www.eclipse.org/mat/downloads.php

  • 若使用eclipse插件安装,help -> install new soft点击ADD,在弹出框中添加插件地址:http://download.eclipse.org/mat/1.9.0/update-site/,也可以直接在下载页面下载离线插件包,以离线方式安装。
  • 也可以选择独立安装
3)MAT相关概念说明
1 内存泄漏与内存溢出
  • 内存泄露:对象已经没用了(不被任何程序逻辑所需要),还存在被根元素引用的情况,无法通过垃圾收集器进行自动回收,需要通过找出泄漏的代码位置和原因,才好确定解决方案;
  • 内存溢出:内存中的对象都还存活着,JVM的堆分配空间不足,需要检查堆设置大小(-Xmx与-Xms),代码是否存在对象生命周期太长、持有状态时间过长的情况。
2 引用(强引用,软引用,弱引用,虚引用)
  • Strong Ref(强引用):强可达性的引用,对象保存在内存中,只有去掉强可达,对象才被回收,通常我们编写的代码都是Strong Ref。
  • Soft Ref(软引用):对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。一般可用来实现缓存,通过java.lang.ref.SoftReference类实现。
  • Weak Ref(弱引用):比Soft Ref更弱,当发现不存在Strong Ref时,立刻回收对象而不必等到内存吃紧的时候。通过java.lang.ref.WeakReference和java.util.WeakHashMap类实现。
  • Phantom Ref(虚引用):根本不会在内存中保持任何对象,你只能使用Phantom Ref本身。一般用于在进入finalize()方法后进行特殊的清理过程,通过 java.lang.ref.PhantomReference实现。
3 shallow heap及retained heap
  • shallow heap:对象本身占用内存的大小,也就是对象头加成员变量(不是成员变量的值)的总和,如一个引用占用32或64bit,一个integer占4bytes,Long占8bytes等。如简单的一个类里面只有一个成员变量int i,那么这个类的shallo size是12字节,因为对象头是8字节,成员变量int是4字节。常规对象(非数组)的Shallow size有其成员变量的数量和类型决定,数组的shallow size有数组元素的类型(对象类型、基本类型)和数组长度决定。
  • retained heap:如果一个对象被释放掉,那会因为该对象的释放而减少引用进而被释放的所有的对象(包括被递归释放的)所占用的heap大小,即对象X被垃圾回收器回收后能被GC从内存中移除的所有对象之和。相对于shallow heap,Retained heap可以更精确的反映一个对象实际占用的大小(若该对象释放,retained heap都可以被释放)。
4 outgoing references与incoming references
  • outgoing references :表示该对象的出节点(被该对象引用的对象)。
  • incoming references :表示该对象的入节点(引用到该对象的对象)。
5 Dominator Tree

将对象树转换成Dominator Tree能帮助我们快速的发现占用内存最大的块,也能帮我们分析对象之间的依赖关系。Dominator Tree有以下几个定义:

  • 对象X Dominator(支配)对象Y,当且仅当在对象树中所有到达Y的路径都必须经过X
  • 对象Y的直接Dominator,是指在对象树中距离Y最近的Dominator
  • Dominator tree利用对象树构建出来。在Dominator tree中每一个对象都是他的直接Dominator的子节点。

对象树和Dominator tree的对应关系如下:

如上图,因为A和B都引用到C,所以A释放时,C内存不会被释放。所以这块内存不会被计算到A或者B的Retained Heap中,因此,对象树在转换成Dominator tree时,会A、B、C三个是平级的。

4)MAT工具使用
  • 分析内存溢出
  • 分析内存泄露
  • 查看对象个数及对象内存占用
  • 观察对象回收后释放空间大小
  • 观察线程栈
3.2.3 GCViewer

GCViewer是一款开源的GC日志分析工具。项目的 GitHub 主页对各个指标提供了完整的描述信息 需要安装jdk才能使用。借助GCViewer日志分析工具,可以非常直观地分析出待调优点。可从以下几方面来分析:

  • Memory:分析Totalheap、Tenuredheap、Youngheap内存占用率及其他指标,理论上内存占用率越小越好;

  • Pause:分析Gc pause、Fullgc pause、Total pause三个大项中各指标,理论上GC次数越少越好,GC时长越小越好;

配置开启GC日志

  • some support for OpenJDK 9 / 10 unified logging format -Xlog:gc:, the following configurations will work
    • -Xlog:gc:file=“path-to-file” (uses defaults)
    • -Xlog:gc=info:file=“path-to-file”:tags,uptime,level (minimum configuration needed)
    • -Xlog:gc*=trace:file=“path-to-file”:tags,time,uptime,level (maximum configuration supported, additional tags ok, but ignored; additional decorations will break parsing)
  • Oracle JDK 1.8 -Xloggc: [-XX:+PrintGCDetails] [-XX:+PrintGCDateStamps]
  • Sun / Oracle JDK 1.7 with option -Xloggc: [-XX:+PrintGCDetails] [-XX:+PrintGCDateStamps]

用法

下载https://github.com/chewiebug/GCViewer/releases

# 分析gc日志,打开图形化界面
java -jar gcviewer-1.36.jar gc.log
# 分析gc日志,不打卡图形化界面,将结果直接生成
java -jar gcviewer-1.36.jar gc.log summary.csv chart.png

图表 + 摘要

统计图表

顶部的黑色线都代表Full GC,也可以理解为Major GC,是根据日志中的CMS GC统计的;底部灰色线代表的是Minor GC。

摘要summary

3.2.4 Arthas

下一步就该使用 JVM 命令进行问题定位了,但很多研发可能由于自身工作经验不足、对 Java 内存模型理解不深、尚未掌握 JVM 排查命令等原因对 JVM 相关排查畏手畏脚,不够自信,进而影响排查进度。针对这种情况,本文推荐一款开源的 Java 诊断工具,对 JVM 不熟的研发可以尝试学习使用下。相对 JVM 命令来说简单多了。

Arthas 是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。

当你遇到以下类似问题而束手无策时,Arthas 可以帮助你解决:

  • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  • 是否有一个全局视角来查看系统的运行状况?
  • 有什么办法可以监控到 JVM 的实时运行状态?
  • 怎么快速定位应用的热点,生成火焰图?

Arthas 支持 JDK 6+,支持 Linux、Mac、Winodws,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

1)下载安装与启动
# 下载arthas-boot.jar
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
# 打印帮助信息:
java -jar arthas-boot.jar -h
# 启动
java -jar arthas-boot.jar
# 选择应用java进程:
    [INFO] arthas-boot version: 3.5.3
    [INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
    * [1]: 31480 org.apache.catalina.startup.Bootstrap
      [2]: 30108 /root/hero_web-1.0-SNAPSHOT-default.jar
# Demo进程是第2个,则输入2,再输入回车/enter。Arthas会attach到目标进程上,并输出日志:
[INFO] Start download arthas from remote server: https://arthas.aliyun.com/download/3.5.4?mirror=aliyun
[INFO] Download arthas success.
[INFO] arthas home: /root/.arthas/lib/3.5.4/arthas
[INFO] Try to attach process 30108
[INFO] Attach process 30108 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                                

wiki       https://arthas.aliyun.com/doc                                        
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html                  
version    3.5.4                                                                
main_class                                                                      
pid        30108                                                                
time       2021-10-12 11:24:34                                                  

[arthas@30108]$
2)Arthas 常见命令
  • jvm:查看当前 JVM 的信息
  • thread:查看当前 JVM 的线程堆栈信息,
    • -b 选项可以一键检测死锁
    • -n 指定最忙的前N个线程并打印堆栈
  • trace:方法内部调用路径,并输出方法路径上的每个节点上耗时,服务间调用时间过长时使用
  • stack:输出当前方法被调用的调用路径
  • Jad:反编译指定已加载类的源码,反编译便于理解业务
  • logger:查看和修改 logger,可以动态更新日志级别

支持管道:

Arthas支持使用管道对上述命令的结果进行进一步的处理,如sm java.lang.String * | grep 'index'

  • grep——搜索满足条件的结果
  • plaintext——将命令的结果去除ANSI颜色
  • wc——按行统计输出结果

后台异步任务:

当线上出现偶发的问题,比如需要watch某个条件,而这个条件一天可能才会出现一次时,异步后台任务就派上用场了,详情请参考这里

  • 使用 > 将结果重写向到日志文件,使用 & 指定命令是后台运行,session断开不影响任务执行(生命周期默认为1天)
  • jobs——列出所有job
  • kill——强制终止任务
  • fg——将暂停的任务拉到前台执行
  • bg——将暂停的任务放到后台执行

用户数据回报:

  • 3.1.4版本后,增加了用户数据回报功能,方便统一做安全或者历史数据统计。

  • 在启动时,指定stat-url,就会回报执行的每一行命令,比如: ./as.sh --stat-url 'http://192.168.10.11:8080/api/stat'

  • 在tunnel server里有一个示例的回报代码,用户可以自己在服务器上实现

  • 这里只列出常用命令,完整列表参考命令列表:

https://alibaba.github.io/arthas/commands.html

其他特性

  • 异步命令支持
  • 执行结果存日志
  • 批处理的支持
  • ognl表达式的用法说明

Arthas 使用上相对 JVM 命令简单很多,即便是工作年限不多的小伙伴学起来也很快。熟练使用 Arthas 应该能诊断出大部分线上应用问题,但生产环境通常不允许擅自拷贝 jar 包,而且 Arthas 会拖慢应用本身,如果条件不允许,又该如何诊断呢?这边简单介绍下 jdk 自带的命令行工具。

3)查看dashboard

输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。

4)查看线程thread

通过thread命令来获取到应用进程的线程信息

thread -1会打印线程统计信息。

5) 反编译已加载类源码

运行期通过jad来反编译项目代码

6)监听运行时方法的返回值watch

通过watch命令来查看com.hero.web.user.controller#UserController函数的返回值:

watch com.hero.web.user.controller.UserController findByUsername returnObj
7)退出

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

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

3.3 JVM参数:标准参数、非标准参数、不稳定参数

在JVM调整过程中,主要是对JVM参数做的调整,以下我们队JVM主要参数做逐一介绍。JVM参数有很多,其实我们直接使用默认的JVM参数,不去修改都可以满足大多数情况。但是如果你想在有限的硬件资源下,部署的系统达到最大的运行效率,那么进行相关的JVM参数设置是必不可少的。下面我们就来对这些JVM参数进行详细的介绍。

JVM参数主要分为以下三种:标准参数、非标准参数、不稳定参数。

3.3.1 标准参数

标准参数,顾名思义,标准参数中包括功能以及输出的结果都是很稳定的,基本上不会随着JVM版本的变化而变化。标准参数以-开头,如:java -version、java -jar等,通过java -help可以查询所有的标准参数,

我们可以通过 -help 命令来检索出所有标准参数。

-help 也是一个标准参数,再比如使用比较多的 -version也是。

3.3.2 非标准参数

非标准参数以-X开头,是标准参数的扩展。对应前面讲的标准化参数,这是非标准化参数。表示在将来的JVM版本中可能会发生改变,但是这类以-X开始的参数变化的比较小。

我们可以通过 Java -X 命令来检索所有-X 参数。

我们可以通过设置非标准参数来配置堆的内存分配,常用的非标准参数有:

  1. -Xms堆内存的最小值:默认值是总内存/64(且小于1G),默认情况下,当堆中可用内存小于40%(这个值可以用-XX: MinHeapFreeRatio 调整,如-X:MinHeapFreeRatio=30)时,堆内存会开始增加,一直增加到-Xmx的大小。
  2. -Xmx堆内存的最大值:默认值是总内存/64(且小于1G),如果Xms和Xmx都不设置,则两者大小会相同,默认情况下,当堆中可用内存大于70%时,堆内存会开始减少,一直减小到-Xms的大小;
  3. -Xmn新生代内存的最大值:包括Eden区和两个Survivor区的总和,写法如:-Xmn1024,-Xmn1024k,-Xmn1024m,-Xmn1g
  4. **-Xss每个线程的栈内存:**默认1M,一般来说是不需要改的。
  5. -Xloggc:file与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中,文件的位置最好在本地,以避免网络的潜在问题。
3.3.3 不稳定参数

这是我们日常开发中接触到最多的参数类型。这也是非标准化参数,相对来说不稳定,随着JVM版本的变化可能会发生变化,主要用于JVM调优和debug。

不稳定参数以-XX 开头,此类参数的设置很容易引起JVM 性能上的差异,使JVM存在极大的不稳定性。如果此类参数设置合理将大大提高JVM的性能及稳定性。

不稳定参数分为三类:

  • 性能参数:用于JVM的性能调优和内存分配控制,如内存大小的设置;

  • 行为参数:用于改变JVM的基础行为,如GC的方式和算法的选择;

  • 调试参数:用于监控、打印、输出jvm的信息;

不稳定参数语法规则:

  1. 布尔类型参数值:

    1. -XX:+ '+'表示启用该选项
    2. -XX:- '-'表示关闭该选项
    3. 示例:-XX:+UseG1GC:表示启用G1垃圾收集器
  2. 数字类型参数值:

    1. -XX:=给选项设置一个数字类型值,可跟随单位,例如:'m’或’M’表示兆字节;'k’或’K’千字节;'g’或’G’千兆字节。32K与32768是相同大小的。
    2. 示例:-XX:MaxGCPauseMillis=500 :表示设置GC的最大停顿时间是500ms
  3. 字符串类型参数值:

    1. -XX:=给选项设置一个字符串类型值,通常用于指定一个文件、路径或一系列命令列表。
    2. 示例:-XX:HeapDumpPath=./dump.core
  4. -Xloggc:file与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中,文件的位置最好在本地,以避免网络的潜在问题。

3.3.3 不稳定参数

这是我们日常开发中接触到最多的参数类型。这也是非标准化参数,相对来说不稳定,随着JVM版本的变化可能会发生变化,主要用于JVM调优和debug。

不稳定参数以-XX 开头,此类参数的设置很容易引起JVM 性能上的差异,使JVM存在极大的不稳定性。如果此类参数设置合理将大大提高JVM的性能及稳定性。

不稳定参数分为三类:

  • 性能参数:用于JVM的性能调优和内存分配控制,如内存大小的设置;

  • 行为参数:用于改变JVM的基础行为,如GC的方式和算法的选择;

  • 调试参数:用于监控、打印、输出jvm的信息;

不稳定参数语法规则:

  1. 布尔类型参数值:
    1. -XX:+ '+'表示启用该选项
    2. -XX:- '-'表示关闭该选项
    3. 示例:-XX:+UseG1GC:表示启用G1垃圾收集器
  2. 数字类型参数值:
    1. -XX:=给选项设置一个数字类型值,可跟随单位,例如:'m’或’M’表示兆字节;'k’或’K’千字节;'g’或’G’千兆字节。32K与32768是相同大小的。
    2. 示例:-XX:MaxGCPauseMillis=500 :表示设置GC的最大停顿时间是500ms
  3. 字符串类型参数值:
    1. -XX:=给选项设置一个字符串类型值,通常用于指定一个文件、路径或一系列命令列表。
    2. 示例:-XX:HeapDumpPath=./dump.core

你可能感兴趣的:(jvm,python,开发语言)