1. 工具概述

使用上一章命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但它们存在下列局限:
1)无法获取方法级别的分析数据,如方法间的调用关系、各方法的调用次数和调用时间
等(这对定位应用性能瓶颈至关重要)。
2)要求用户登录到目标Java应用所在的宿主机上,使用起来不是很方便。
3)分析数据通过终端输出,结果展示不够直观。

为此,JDK提供了一些内存泄漏的分析工具,如jconsole,jvisualvm等,用于辅助开发人员定位问题,但是这些工具很多时候并不足以满足快速定位的需求。所以这里我们介绍的工具相对多一些、丰富一些。

图形化综合诊断工具年
JDK自带的工具
jconsole:JDK自带的可视化监控工具。查看Java应用程序的运行概况、监控堆信息、永久区(或元空间)使用情况、类加载情况等
位置: jdk lbinljconsole.exe
Visual VM:Visual VM是一个工具,它提供了一个可视界面,用于查看Java虚拟机上运行的基于Java技术的应用程序的详细信息。
位置:jdk \binljvisualvm.exe
JMC:Java Mission Control,内置Java Flight Recorder。能够以极低的性能开销收集Java虚拟机的性能数据。

第三方工具
MAT: MAT(Memory Analyzer Tool)是基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。Eclipse的插件形式
Profiler:商业软件,需要付费。功能强大。与 VisualVM类似
Arthas:Alibaba开源的Java诊断工具。深受开发者喜爱。
Btrace:Java运行时追踪工具。可以在不停机的情况下,跟踪指定的方法调用、构造函数调用和系统内存等信息。

2. JConsole

从Java5开始,在JDK中自带的java监控和管理控制台。
用于对VM中内存、线程和类等的监控,是一个基于JMX(java management extensions)的GUI性能监控工具。

官方教程:

3. Visual VM

基本概述(重点掌握)
Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具。
它集成了多个JDK命令行工具,使用visual VM可用于显示虚拟机进程及进程的配置和环境信息
(jps,jinfo),监视应用程序的CPU、GC、堆、方法区及线程的信息(jstat、jstack)等,甚至代替JConsole。
在DK 6 Update 7以后,Visual VM便作为JDK的一部分发布(VisualVM 在JDK/bin目录下),即:它完全免费。|
此外,Visual VM也可以作为独立的软件安装:

首页

在jdk安装目录中找到jvisualvm.exe,然后双击执行即可。或打开DOS窗口,输入jvisualvm就可以打开该软件。
单独安装叫Visual VM,jdk自带叫jvisualvm。

安装插件
Visual VM的一大特点是支持插件扩展,并且插件安装非常方便。我们既可以通过离线下载插件文件*.nbm,然后在Plugin对话框的已下载页面下,添加已下载的插件。也可以在可用插件页面下,在线安装插件。(这里建议安装上:VisualGC)

插件地址:
本地连接

使用本地连接,在idea启动OOMTest.java,在DOS窗口输入jvisualvm,然后选择OOMTest,进入监控界面。
导出heapdump、threaddump

先点击右侧堆dump,然后点击左侧的heapdump文件,将其保存到桌面。
线程dump
先点击线程dump,然后点击左侧的threaddump,保存到桌面。
导入heapdump、threaddump
点击文件,选择装入,找到文件位置,选择要导入的文件类型

导入heapdump
分析过程:十分重要
点击查找,找到最大的对象
点击#84进入,发现ArrayList里面存储的就是#1856
选中ArrayList,点击在线程中显示。
直接定位到具体的类的方法:at com.atguigu.springcloud.jvm.OOMTest.main(OOMTest.java:16)
如此便定位到了堆中最大的对象的位置。然后就可以去翻看代码,查看代码逻辑是否有问题。

配合下面的步骤,具体定位到原因。

点击#1856
点击#569,发现Object数组里面存储的是Picture
点击#887,发现Picture里面有byte[ ]

由此,我们遍发现了是OOMTest类中的main方法中的list对象中存储的Picture对象太多导致的内存占用过高。

导入threaddump
文件–>装入–>修改文件类型
jvisualvm分析线程dump好像不怎么方便的样子,暂且点到为止。

4. Eclipse MAT

4.1 基本概述

MAT(Memory Analyzer Tool)工具是一款功能强大的Java堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。
MAT是基于Eclipse开发的,不仅可以单独使用,还可以作为插件的形式嵌入在Eclipse中使用。是一款免费的性能分析工具,使用起来非常方便。

下载:

只要确保机器上装有JDK并配置好相关的环境变量,MAT可正常启动。还可以在Eclipse中以插件的方式安装:

4.2 获取dump文件

dump文件内容
MAT可以分析heap dump文件。在进行内存分析时,只要获得了反映当前设备内存映像的hprof文件,通过MAT打开就可以直观地看到当前的内存信息。
一般说来,这些内存信息包含:
所有的对象信息,包括对象实例、成员变量、存储于栈中的基本类型值和存储于堆中的其他对象的引用值。
所有的类信息,包括classloader、类名称、父类、静态变量等.
GCRoot到所有的这些对象的引用路径
线程信息,包括线程的调用栈及此线程的线程局部变量(TLS)

说明1:
MAT不是一个万能工具,它并不能处理所有类型的堆存储文件。但是比较主流的厂家和格式,例如Sun,HP,SAP所采用的 HPROF 二进制堆存储文件,以及IBM的 PHD堆存储文件等都能被很好的解析。
说明2:
最吸引人的还是能够快速为开发人员生成内存泄漏报表,方便定位问题和分析问题。虽然MAT有如此强大的功能,但是内存分析也没有简单到一键完成的程度,很多内存问题还是需要我们从MAT展现给我们的信息当中通过经验和直觉来判断才能发现。

获取dump文件
方法一:通过前一章介绍的 jmap工具生成,可以生成任意一个java进程的dump文件
方法二:通过配置JVM参数生成。
选项"-XX:+HeapDumpOnoutOfMemoryError”或"-XX:+HeapDumpBeforeFullGC"
选项"-XX :HeapDumpPath"所代表的含义就是当程序出现OutOfMemory时,将会在相应的目录下生成一份dump文件。如果不指定选项“-XX:HeapDumpPath”则在当前目录下生成dump文件。
对比:考虑到生产环境中几乎不可能在线对其进行分析,大都是采用离线分析,因此使用jmap+MAT工具是最常见的组合。
方法三:使用VisualVM可以导出堆dump文件
方法四:使用MAT既可以打开一个已有的堆快照,也可以通过MAT直接从活动Java程序中导出堆快照。该功能将借助jps列出当前正在运行的Java 进程,以供选择并获取快照。

4.3 分析堆dump文件

打开堆dump文件

如果是第一次打开,就选第一个,否则,选最后一个。

MAT菜单栏

Histogram(直方图)

寻找指定对象的GC ROOTS(只看强引用)
也可以直接搜索
查看所有的线程
下图中的local指的就是局部变量
获得对象互相引用的关系

Leak Suspects(内存泄露分析)
想要看详情可以点击上图的Details>>

浅堆与深堆
浅堆(Shallow Heap)是指一个对象所消耗的内存。在32位系统中,一个对象引用会占据4个字节,一个int类型会占据4个字节,long型变量会占据8个字节,每个对象头需要占用8个字节。根据堆快照格式不同,对象的大小可能会向8字节进行对齐。

以String为例: 2个int值共占8字节,对象引用占用4字节,对象头8字节,合计20字节,
故占24字节。(jdk7中)
int hash32 0
int hash 0
ref value C:Users\Administrat
这24字节为String对象的浅堆大小。它与String的value实际取值无关,无论字符串长度如何,浅堆大小始终是24字节。

保留集(Retained Set):
对象A的保留集指当对象A被垃圾回收后,可以被释放的所有的对象集合(包括对象A本身),即对象A的保留集可以被认为是只能通过对象A被直接或间接访问到的所有对象的集合。通俗地说,就是指仅被对象A所持有的对象的集合。

深堆(Retained Heap):
深堆是指对象的保留集中所有的对象的浅堆大小之和。
注意:浅堆指对象本身占用的内存,不包括其内部引用对象的大小。一个对象的深堆指只能通过该对象访问到的(直接或间接)所有对象的浅堆之和,即对象被回收后,可以释放的真实空间。


支配树(Dominator Tree)
支配树的概念源自图论。
MAT提供了一个称为支配树(Dominator Tree)的对象图。支配树体现了对象实例间的支配关系。在对象引用图中,所有指向对象B的路径都经过对象A,则认为对象A支配对象B。如果对象A是离对象B最近的一个支配对象,则认为对象A为对象B的直接支配者。支配树是基于对象间的引用图所建立的,它有以下基本性质:
对象A的子树(所有被对象A支配的对象集合)表示对象A的保留集(retained set),即深堆。
如果对象A支配对象B,那么对象A的直接支配者也支配对象B。
支配树的边与对象引用图的边不直接对应。

如下图所示:左图表示对象引用图,右图表示左图所对应的支配树。对象A和B由根对象直接支配,由于在到对象c的路径中,可以经过A,也可以经过B,因此对象c的直接支配者也是根对象。对象F与对象D相互引用,因为到对象F的所有路径必然经过对象D,因此,对象D是对象F的直接支配者。而到对象D的所有路径中,必然经过对象c,即使是从对象F到对象D的引用,从根节点出发,也是经过对象C的,所以,对象D的直接支配者为对象C。

注意:
从“对象引用图“到”支配树”
支配者:如果要到达对象B,必须经过对象A,那么对象A就是对象B的支配者,可以想到支配者大于等于1。
直接支配者:在支配者中距离对象B最近的对象A就是对象B的直接支配者,直接支配者不一定就是对象B的上一级,直接支配者只有一个。
支配树是怎么画?支配树中的对象与对象之间的关系就是直接支配关系,也就是上一级是下一级的直接支配者,只要按照这样的方式来作图,肯定从“对象引用图“到”支配树”。
内存泄露


内存泄漏与内存溢出的关系:
内存泄漏( memory leak )
申请了内存用完了不释放,比如一共有1024M 的内存,分配了512M的内存一直不回收,那么可以用的内存只有512M了,仿佛泄露掉了一部分;通俗一点讲的话,内存泄漏就是【占着茅坑不拉shil. lI

内存溢出(out of memory)
申请内存时,没有足够的内存可以使用;
通俗一点儿讲,一个厕所就三个坑,有两个占着茅坑不走的(内存泄漏)﹐剩下最后一个坑,厕所表示接待压力很大,这时候一下子来了两个人,坑位(内存)就不够了,内存泄漏变成内存溢出了。
可见,内存泄漏和内存溢出的关系:内存泄漏的增多,最终会导致内存溢出。量变引起质变

泄漏的分类
经常发生:发生内存泄露的代码会被多次执行,每次执行,泄露一块内存;
偶然发生:在某些特定情况下才会发生
一次性:发生内存泄露的方法只会执行一次;
隐式泄漏:一直占着内存不释放,直到执行结束;严格的说这个不算内存泄漏,因为最终释放掉了,但是如果执行时间特别长,也可能会导致内存耗尽。
Java中内存泄露的8种情况
1)静态集合类
静态集合类,如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与JVM程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。简单而言,长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。
2)单例模式
单例模式,和静态集合导致内存泄露的原因类似,因为单例的静态特性,它的生命周期和JVM的生命周期一样长,所以如果单例对象如果持有外部对象的引用。那么这个外部对象也不会被回收,那么就会造成内存泄漏。

3)内部类持有外部类
内部类持有外部类,如果一个外部类的实例对象的方法返回了一个内部类的实例对象。这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄漏。

4)各种连接,如数据库连接、网络连接和IO连接等
各种连接,如数据库连接、网络连接和IO连接等。
在对数据库进行操作的过程中,首先需要建立与数据库的连接,当不再使用时,需要调用close方法来释放与数据库的连接。只有连接被关闭后,垃圾回收器才会回收对应的对象。否则,如果在访问数据库的过程中,对Connection、Statement或ResultSet不显性地关闭,将会造成大量的对象无法被回收,从而引起内存泄漏。
5)变量不合理的作用域

6)改变哈希值
改变哈希值,当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了。|
否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄漏。
这也是string为什么被设置成了不可变类型,我们可以放心地把 string存入 HashSet,或者把String 当做HashMap 的key值;
当我们想把自己定义的类保存到散列表的时候,需要保证对象的 hashCode不可变。

/*** 演示内存泄漏** @author shkstart* @create 14:43*/
public class ChangeHashCode {public static void main(String[] args) {HashSet set = new HashSet();Person p1 = new Person(1001, "AA");Person p2 = new Person(1002, "BB");set.add(p1);set.add(p2);p1.name = "CC";//导致了内存的泄漏set.remove(p1); //删除失败System.out.println(set);set.add(new Person(1001, "CC"));System.out.println(set);set.add(new Person(1001, "AA"));System.out.println(set);}
}class Person {int id;String name;public Person(int id, String name) {this.id = id;this.name = name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof Person)) return false;Person person = (Person) o;if (id != person.id) return false;return name != null ? name.equals(person.name) : person.name == null;}@Overridepublic int hashCode() {int result = id;result = 31 * result + (name != null ? name.hashCode() : 0);return result;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +'}';}
}

7)缓存泄露
内存泄漏的另一个常见来源是缓存,一旦你把对象引用放入到缓存中,他就很容易遗忘。比如:之前项目在一次上线的时候,应用启动奇慢直到夯死,就是因为代码中会加载一个表中的数据到缓存(内存)中,测试环境只有几百条数据,但是生产环境有几百万的数据。
对于这个问题,可以使用WeakHashMap代表缓存,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值。

/*** 演示内存泄漏** @author shkstart* @create 14:53*/
public class MapTest {static Map wMap = new WeakHashMap();static Map map = new HashMap();public static void main(String[] args) {init();testWeakHashMap();testHashMap();}public static void init() {String ref1 = new String("obejct1");String ref2 = new String("obejct2");String ref3 = new String("obejct3");String ref4 = new String("obejct4");wMap.put(ref1, "cacheObject1");wMap.put(ref2, "cacheObject2");map.put(ref3, "cacheObject3");map.put(ref4, "cacheObject4");System.out.println("String引用ref1,ref2,ref3,ref4 消失");}public static void testWeakHashMap() {System.out.println("WeakHashMap GC之前");for (Object o : wMap.entrySet()) {System.out.println(o);}try {System.gc();TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("WeakHashMap GC之后");for (Object o : wMap.entrySet()) {System.out.println(o);}}public static void testHashMap() {System.out.println("HashMap GC之前");for (Object o : map.entrySet()) {System.out.println(o);}try {System.gc();TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("HashMap GC之后");for (Object o : map.entrySet()) {System.out.println(o);}}}
/*** 结果* String引用ref1,ref2,ref3,ref4 消失* WeakHashMap GC之前* obejct2=cacheObject2* obejct1=cacheObject1* WeakHashMap GC之后* HashMap GC之前* obejct4=cacheObject4* obejct3=cacheObject3* Disconnected from the target VM, address: '127.0.0.1:51628', transport: 'socket'* HashMap GC之后* obejct4=cacheObject4* obejct3=cacheObject3**/


实际工作中并不建议使用WeakHashMap,可以使用HashMap,限制HashMap的数量,以及不使用了及时清空即可。

8)监听器和回调
内存泄漏第三个常见来源是监听器和其他回调,如果客户端在你实现的API中注册回调,却没有显示的取消,那么就会积聚。
需要确保回调立即被当作垃圾回收的最佳方法是只保存它的弱引用,例如将他们保存成为weakHashMap护的键。

内存泄露案例分析

public class Stack {private Object[] elements;private int size = 0;private static final int DEFAULT_INITIAL_CAPACITY = 16;public Stack() {elements = new Object[DEFAULT_INITIAL_CAPACITY];}public void push(Object e) { //入栈ensureCapacity();elements[size++] = e;}//存在内存泄漏
//    public Object pop() { //出栈
//        if (size == 0)
//            throw new EmptyStackException();
//        return elements[--size];
//    }public Object pop() {if (size == 0)throw new EmptyStackException();Object result = elements[--size];elements[size] = null;return result;}private void ensureCapacity() {if (elements.length == size)elements = Arrays.copyOf(elements, 2 * size + 1);}
}

上述程序并没有明显的错误,但是这段程序有一个内存泄漏,随着GC活动的增加,或者内存占用的不断增加,程序性能的降低就会表现出来,严重时可导致内存泄漏,但是这种失败情况相对较少。代码的主要问题在pop函数。
当进行大量的pop操作时,由于引用未进行置空,gc是不会释放的。
如果栈先增长,然后收缩,那么从栈中弹出的对象将不会被当作垃圾回收,即使程序不再使用栈中的这些队象,他们也不会回收,因为栈中仍然保存这对象的引用,俗称过期引用,这个内存泄露很隐蔽。

所以当对象出栈后及时将引用置空。elements[size] = null;防止内存泄露。

支持使用OQL语言查询对象信息
SELECT子句:

FROM子句:

WHERE子句

内置对象与方法

5. JProfiler

5.1 基本概述

在运行Java的时候有时候想测试运行时占用内存情况,这时候就需要使用测试工具查看了。在
eclipse里面有 Eclipse Memory Analyzer too1(MAT)插件可以测试,而在IDEA中也有这么一个插件,就是JProfiler。
JProfiler是由 ej-technologies公司开发的一款 Java应用性能诊断工具。功能强大,但是收费。

官网下载地址:

特点:
使用方便、界面操作友好(简单且强大)·对被分析的应用影响小(提供模板).
CPU,Thread ,Memory分析功能尤其强大
支持对jdbc , noSql,jsp, servlet,socket等进行分析
支持多种模式(离线,在线)的分析
支持监控本地、远程的JVM
跨平台,拥有多种操作系统的安装版本

5.2 安装与配置

下载与安装
使用特别版直接安装,然后使用注册码激活。

5.2.1 JProfiler中配置IDEA


最终点击OK即可。

5.2.2 IDEA集成JProfiler

在idea中直接安装插件即可,如果下载不下来,当然也可以使用jar包安装插件。我的直接下载成功了,然后重启idea。
11版本的JProfiler插件直接链接了idea,不用再手动关联了。

5.3 具体使用

5.3.1 软件操作指南

5.3.2 数据采集方式

JProfier数据采集方式分为两种:Sampling(样本采集)和Instrumentation(重构模式)
Instrumentation:这是Profiler全功能模式。在class加载之前,JProfier把相关功能代码写入到需要分析的class的bytecode中,对正在运行的jvm有一定影响。
优点:功能强大。在此设置中,调用堆栈信息是准确的。
缺点:若要分析的class较多,则对应用的性能影响较大,CPU开销可能很高(取决于Filter的控制)。因此使用此模式一般配合Filter使用,只对特定的类或包进行分析

Sampling:类似于样本统计,每隔一定时间(5ms)将每个线程栈中方法栈中的信息统计出来。
优点:对CPU的开销非常低,对应用影响小(即使你不配置任何Filter)·缺点:一些数据/特性不能提供(例如:方法的调用次数、执行时间)

注: JProfiler本身没有指出数据的采集类型,这里的采集类型是针对方法调用的采集类型。因为JProfiler的绝大多数核心功能都依赖方法调用采集的数据,所以可以直接认为是Profiler的数据采集类型。

5.3.3 遥感监测 Telemetries

总览
内存

5.3.4 内存视图 Live Memory


分析内存泄露
什么情况下可能存在内存泄露?

5.3.5 堆遍历 heap walker

1)、分析对象的引用
从all Objects跳转到heap walker
使用选中的对象
看看谁引用了这个对象
找到最终引用的位置

Shallow size、 Retained size、 Deep size

Shallow(浅) size:就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。

Retained(保留) size:是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。

Deep(深) size:包含那些对象的大小。深大小与保留大小的区别在于深大小包含那些存在共享的对象,但是保留大小则不包括。
在图表中展示



2)、导出hprof文件

5.3.6 cpu视图 cpu views

5.3.7 线程视图 threads、监视器&锁 Monitors&locks


5.4 案例分析

代码

public class MemoryLeak {public static void main(String[] args) {while (true) {ArrayList beanList = new ArrayList();for (int i = 0; i < 500; i++) {Bean data = new Bean();data.list.add(new byte[1024 * 10]);//10kbbeanList.add(data);}try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}class Bean {int size = 10;String info = "hello,atguigu";
//     ArrayList list = new ArrayList();static ArrayList list = new ArrayList();
}

使用profiler启动程序
发现内存直线上升
然后在所有对象中标记一下,看看谁增长最快且不能被回收

然后在heap walker中分析
接着在heap walker中选中该对象,并分析是谁在引用当前对象
定位到是谁在引用

翻看代码定位到MemoryLeak和Bean类,发现Bean类中定义了一个静态的list,该list在gc过程中无法被回收。可以考虑将其改为非静态或者在执行完成后将该list清空。 Bean.list.clear();
代码修改后内存回收如下图,说明list可以被回收掉了,内存上去了又下来了,不会一直上升。

6、Arthas

6.1 概述

这两款工具在业界知名度也比较高,他们的优点是可以图形界面上看到各维度的性能数据,使用者根据这些数据进行综合分析,然后判断哪里出现了性能问题。
但是这两款工具也有个缺点,都必须在服务端项目进程中配置相关的监控参数。然后工具通过远程连接到项目进程,获取相关的数据。这样就会带来一些不便,比如线上环境的网络是隔离的,本地的监控工具根本连不上线上环境。并且类似于Jprofiler这样的商业工具,是需要付费的。
那么有没有一款工具不需要远程连接,也不需要配置监控参数,同时也提供了丰富的性能监控数据呢?
今天跟大家介绍一款阿里巴巴开源的性能分析神器Arthas(阿尔萨斯)

Arthas(阿尔萨斯)是Alibaba开源的Java诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪Java代码;实时监控VM状态。
Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的Tab自动补全功能,进一步方便进行问题的定位和诊断。
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
这个类从哪个jar包加载的?为什么会报各种类相关的Exception?
我改的代码为什么没有执行到?难道是我没commit?分支搞错了?
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
是否有一个全局视角来查看系统的运行状况?
有什么办法可以监控到JVM的实时运行状态?怎么快速定位应用的热点,生成火焰图?

基于哪些工具开发而来
greys-anatomy: Arthas代码基于Greys二次开发而来,非常感谢Greys之前所有的工作,以及Greys原作者对Arthas提出的意见和建议!
termd: Arthas的命令行实现基于termd开发,是一款优秀的命令行程序开发框架,感谢termd提供了优秀的框架。
crash: Arthas的文本渲染功能基于crash中的文本渲染功能开发,可以从这里看到源码,感谢crash在这方面所做的优秀工作。
cli: Arthas的命令行界面基于vert.x提供的cli库进行开发,感谢vert.x在这方面做的优秀工作。
compiler Arthas里的内存编绎器代码来源
Apache Commons Net Arthas里的Telnet Client代码来源
JavaAgent:运行在 main方法之前的拦截器,它内定的方法名叫 premain ,也就是说先执行
premain方法然后再执行main方法
ASM:一个通用的Java字节码操作和分析框架。它可以用于修改现有的类或直接以二进制形式动态生成类。ASM提供了一些常见的字节码转换和分析算法,可以从它们构建定制的复杂转换和代码分析工具。ASM提供了与其他Java字节码框架类似的功能,但是主要关注性能。因为它被设计和实现得尽可能小和快,所以非常适合在动态系统中使用(当然也可以以静态方式使用,例如在编译器中)

官方文档

6.2 安装与使用

安装方式一:可以直接在Linux上通过命令下载
可以在官方Github 上进行下载,如果速度较慢,可以尝试国内的码云 Gitee下载。

github下载

Gitee下载

卸载:
在 Linux/Unix/Mac平台删除下面文件:
rm -rf ~/ .arthas/
rm -rf ~/logs/arthas
windows平台直接删除user home下面的.arthas和logs/arthas目录

工程目录:
arthas-agent:基于JavaAgent技术的代理
bin:一些启动脚本
arthas-boot: Java版本的一键安装启动脚本
arthas-client: telnet client代码
arthas-common:一些共用的工具类和枚举类
arthas-core:核心库,各种arthas命令的交互和实现
arthas-demo:示例代码
arthas-memorycompiler:内存编绎器代码,Fork fromhttps://github.com/skalogs/SkaETL/tree/master/compiler
arthas-packaging: maven打包相关的
arthas-site: arthas站点
arthas-spy:编织到目标类中的各个切面static:静态资源
arthas-testcase:测试

启动
Arthas只是一个java程序,所以可以直接用java -jar 运行。
执行成功后,arthas提供了一种命令行方式的交互方式,arthas会检测当前服务器上的Java进程,并将进程列表展示出来,用户输入对应的编号进行选择,然后回车。

比如:方式1:
java -jar arthas-boot.jar
选择进程(输入[]内编号(不是PID)回车)
[INFO] arthas-boot version: 3.1.4
[INFO] Found existing java process,please choose one and hit RETURN.
*[1]:11616 com.ArthasI[2]:8676[3]:16200 org.jetbrains.jps.cmdline.Launcher[4]: 21032 org.jetbrains.idea.maven.server.RemoteMavenServer
方式2:运行时选择Java进程 PID
java -jar arthas-boot.jar [PID]

退出
最后一行[arthas@7457]$,说明打开进入了监控客户端,在这里就可以执行相关命令进行查看了。
使用quit/exit:退出当前客户端
使用stop/shutdown:关闭arthas服务端,并退出所有客户端。

查看日志:cat ~/logs/arthas/arthas.log
查看帮助:java -jar arthas-boot.jar -h

6.3 相关诊断指令

6.3.1 基础指令

6.3.2 jvm相关

dashboard -i 3000 -n 2:i是时间间隔,ms ; n是打印次数

thread
heapdump --live /home/hello/1.hprof

6.3.3 class/classloader相关

sc

sc com.atguigu.*
sc -d -f com.atguigu.jvm.controller.TestController
sm

sm com.atguigu.jvm.controller.TestController:没带方法就会列出所有的方法
sm -d com.atguigu.jvm.controller.TestController test:带上方法名和-d会显示该方法的详细信息
jad com.atguigu.jvm.controller.TestController test 反编译已加载的指定类

6.3.4 monitor/watch/trace相关

trace指令十分常用,比如某个接口响应迟钝,排查一下性能瓶颈在哪?
启动arthas
java -jar arthas-boot.jar
输入想要监控的服务对应的中括号中的数字

trace com.test.study.TestController test

耗时最长的方法会被标红,然后重点分析该方法的代码,进行优化

诊断结束,执行stop命令,会还原所有被增强过的类。

6.3.5 profiler/火焰图

profiler start:启动 profiler
profiler getSamples:获取已采集的 sample 的数量
profiler status:查看 profiler 状态
profiler stop --file /home/hello/1.html:停止 profiler,默认情况下,结果文件是html格式,也可以用–format参数指定。或在–file参数里用文件名指名格式。
sz 1.html:下载1.html并保存到桌面
使用浏览器打开1.html


参考博客

火焰图,简单通过x轴横条宽度来度量时间指标,y轴代表线程栈的层次。

7 Java Misssion Control





Java Flight Recorder


方式1:使用-XX:StartFlightRecording=参数

方式2:使用jcmd的JFR.*子命令

方式3:JMC的JFR插件

/*** -Xms600m -Xmx600m -XX:+UnlockCommercialFeatures -XX:+FlightRecorder* @author shkstart  shkstart@126.com* @create 2020  21:12*/
public class OOMTest {public static void main(String[] args) {ArrayList<Picture> list = new ArrayList<>();while(true){try {Thread.sleep(120);} catch (InterruptedException e) {e.printStackTrace();}list.add(new Picture(new Random().nextInt(1024 * 1024)));}}
}class Picture{private byte[] pixels;public Picture(int length) {this.pixels = new byte[length];}
}

取样结束后会自动在JMC中打开

注:本文是学习 尚硅谷宋红康JVM全套教程(详解java虚拟机)所做笔记。

JVM监控及诊断工具-GUI相关推荐

  1. 性能监控与调优篇之【3. JVM 监控及诊断工具-GUI 篇】

    文章目录 3. JVM 监控及诊断工具-GUI 篇 3.1. 工具概述 3.2. JConsole 3.3. Visual VM 3.4. Eclipse MAT 3.5. JProfiler 3.6 ...

  2. JVM监控及诊断工具-GUI篇

    3.JVM监控及诊断工具-GUI篇 一.工具概述 使用上一章命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但它们存在下列局限: 1.无法获取方法级别的分析数据,如方法间的调用关系.各方 ...

  3. 20.JVM监控以及诊断工具-GUI篇

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 20. JVM监控及诊断工具-GUI篇 20.1. 工具概述 使用上一章命令行工具或组合能帮您获取目标Java应用性能相 ...

  4. 干货满满【JVM监控及诊断工具-GUI篇】

    [JVM监控及诊断工具-GUI篇] 3.1. 工具概述 使用上一章命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但它们存在下列局限: 1.无法获取方法级别的分析数据,如方法间的调用关系 ...

  5. Day357358359360.JVM监控及诊断工具-GUI -JVM

    JVM监控及诊断工具-GUI 实际中,你下面有1-2款会用即可 一.工具概述 二.JConsole 了解 1.基本概述 2.启动 在jdk安装目录中找到jconsole.exe,双击该可执行文件就可以 ...

  6. JVM 学习笔记二十六、JVM监控及诊断工具-GUI篇

    二十六.JVM监控及诊断工具-GUI篇 1.工具概述 使用上一张命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但他们存在下列局限: (1)无法获取方法级别的分析数据,如方法间的调用关系 ...

  7. 第24章 JVM监控及诊断工具-GUI篇

    第24章 JVM监控及诊断工具-GUI篇 来自尚硅谷宋红康老师讲解的JVM:bilibili链接 1 工具概述 使用上一张命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但他们存在下列局 ...

  8. JVM学习笔记之-JVM性能监控-JVM监控及诊断工具-GUI方式-Visual VM-JProfiler-Arthas

    00-谈GUI工具前的补充 补充1:内存泄漏 内存泄漏的理解与分类 何为内存泄漏( memory leak) 可达性分析算法来判断对象是否是不再使用的对象,本质都是判断一个对象是否还被引用.那么对于这 ...

  9. 15、JVM监控及诊断工具-GUI篇

    文章目录 第1章.工具概述 第2章.jConsole 1.基本概述 2.启动 3.三种连接方式 [1]Local [2]Remote [3]Advanced 4.主要作用 第3章.Visual VM ...

  10. JVM(二十二) -- 性能监控与调优(三) -- JVM监控及诊断工具--GUI篇

    1.工具概述 1.1 图形化总和诊断工具: JDK自带的工具 第三方工具 2. jConsole(了解) 从java5开始,在JDK中自带的java监控和管理控制台. 用于对JVM中内存.线程和类等的 ...

最新文章

  1. 妹子调车为哪般?室外赛道来闯关。
  2. 在计算机上工作用英语怎么说,“Go to work”是“去上班”,那“上夜班”用英语怎么说呢?...
  3. cocos2d-x初探学习笔记(15)--CCOrbitCamera
  4. 如何配置yum源,并安装FTP服务器
  5. 2019年可能是折叠手机爆发的一年:华为、三星、小米已确认 LG“掉队”
  6. MySQL按日期分组统计(按天统计,按月统计)
  7. The method getContextPath() is undefined for the type ServletContext
  8. CSS实现三角形的方法--拓展
  9. linux下编译opendds,求教OpenDDS的交叉编译!
  10. Intel600P三星sm951pm961nvme等固态硬盘安装WIN7教程
  11. Android免费获取短信验证码
  12. Matlab 直方图绘制
  13. 实现jquery双击图片放大
  14. 湖南省岳阳市谷歌高清卫星地图下载
  15. 定时开关机的八种方法
  16. 万物本业互联,一切皆可编程_如何保持专注-互联世界中无干扰的编程
  17. 高新技术企业的八大领域及要点
  18. 六个方法是:指引、预示、安全区、分层、分支和打乱节奏
  19. 万字长文科普:什么是低代码?
  20. 有鹿生活2021年电商行业年度报告

热门文章

  1. 云队友丨如何“优雅”地进行职场沟通?
  2. Agfa的MUSICA说明
  3. 丘成桐:赋比兴、境界与数学
  4. NCH SoundTap Plus for mac(苹果电脑录音软件)
  5. Upload java coed in Ubuntu(在Linux 16上,上传代码)
  6. 鼠标拖曳盒子案例(限定边界)
  7. 《解谜三星堆:开启中华文明之门》-范勇 笔记
  8. Android 设置壁纸流程
  9. Python编辑excel里的文本框
  10. NSN HLR simulator for provisioning in expect