赞
踩
JDK自带的工具
第三方工具
Local:
console连接一个正在本地系统运行的JVM,并且执行程序的和运行Jconsole的需要是同一个用户。Jconsole使用文件系统的授权通过RMI连接器连接到平台的MBean服务器上。这种从本地连接的监控能力只有Sun的JDK具有
Remote:
使用下面的URL通过RMI连接器连接到一个JMX代理,service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi
。JConsole为建立连接,需要在环境变量中设置mx.remote.credentials来指定用户名和密码,从而进行授权。
Advanced:
使用一个特殊的URL连接JMX代理。一般情况使用自己定制的连接器而不是RMI提供的连接器来连接JMX代理,或者是一个使用JDK1.4的实现了JMX和JMX Rmote的应用
方式一:网络下载
方式二:软件的工具栏->插件中直接下载
具体的使用可以看视频、或者自己操作软件学习与使用
概述:(jinfo)
监视
线程
GC
VisualVM中监视和线程的右上角都有Dump按钮,可以对当前JVM的情况进行dump,dump下来后可以点击文件->装入,进行dump文件分析,同时还可以比较两个不同时间段的dump文件
这里不多展示,但是较为重要,记得自己点击用着看看
可以对某一时刻的CPU和内存进行快照,然后查看CPU突然飙高的原因,以及内存中类过多的问题。
主要作用:分析dump文件
主要列举的内存中加载的类的个数,以及占用的浅堆及深堆的大小
点击具体的类可以看到:
分组:
排查GC roots
比较基于b跟a的dump文件的区别:
可用于分析有可能出现内存泄漏的线程
两个用处:
系统中的线程:
局部变量:
分析可能出现的问题:
incoming:被谁引用
outcoming:引用过谁
浅堆:
深堆:当前对象的浅堆大小+所有只由他触及的对象的浅堆大小之和
补充:对象实际大小 (对象所能触及的浅堆大小之和)
代码:
/** * 有一个学生浏览网页的记录程序,它将记录 每个学生访问过的网站地址。 * 它由三个部分组成:Student、WebPage和StudentTrace三个类 * * 获取dump文件:-XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=c:\code\student.hprof * */ public class StudentTrace { static List<WebPage> webpages = new ArrayList<WebPage>(); public static void createWebPages() { for (int i = 0; i < 100; i++) { WebPage wp = new WebPage(); wp.setUrl("http://www." + Integer.toString(i) + ".com"); wp.setContent(Integer.toString(i)); webpages.add(wp); } } public static void main(String[] args) { createWebPages();//创建了100个网页 //创建3个学生对象 Student st3 = new Student(3, "Tom"); Student st5 = new Student(5, "Jerry"); Student st7 = new Student(7, "Lily"); for (int i = 0; i < webpages.size(); i++) { if (i % st3.getId() == 0) st3.visit(webpages.get(i)); if (i % st5.getId() == 0) st5.visit(webpages.get(i)); if (i % st7.getId() == 0) st7.visit(webpages.get(i)); } webpages.clear(); System.gc(); } } class Student { private int id; private String name; private List<WebPage> history = new ArrayList<>(); public Student(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<WebPage> getHistory() { return history; } public void setHistory(List<WebPage> history) { this.history = history; } public void visit(WebPage wp) { if (wp != null) { history.add(wp); } } } class WebPage { private String url; private String content; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
打开生成dump文件:查看线程信息:
浅堆是24是因为student包括3个字段:int4个字节、name4个字节、list是4个字节、对象头8个字节,最后补齐24个字节
具体的student内容:
15个webpage
每个对应152个字节 15*152=2280字节 --> 即为elementData的实际大小
为什么深堆回收的时候只能回收1288呢?
因为比如0、21、42、35、63、70、84既能被7整除,也能被3或者5整除,所以这7个网页在回收的时候是不能被回收的,所以只能回收8*152=1216,跟1288还是差了72;
那么这72个字节是什么?
15个elementData的元素,每个元素4个字节,即60个字节+对象头8个字节+数组本身4个字节 = 72个字节。
MAT支持一种类似于SQL的查询语言OQL(Object Query Language)。OQL使用类SQL语法,可以在堆中进行对象的查找和筛选。
找地址对应的结构,如果直接用student查询的话,可能会查到多个加载器加载的stduent,如果用地址的话查到的就是唯一的我们想要的student
可查看官方文档,做的很好。地址:Jprofiler官方文档
收费、破解版自己下载,此处略。
关闭IDEA
session(会话) -> IDE Integration(IDE集成)
选择自己的idea版本,点击integrate
选择自己的idea的配置文件
完成
选中需要进行监控的程序,检点小蓝点执行:
Jprofiler中就能看到监控信息:
内存泄漏用Sampling方式就ok了。
注意:其中记录对象最好在内存泄漏时使用,因为资源占用较高。
注意上面的SIZE是浅堆。
点击Picture。
查找谁使用Picture或者Picture使用了谁:
查看结果,并根据结果去看对应的图表:
以下是图表的展示情况:
访问树:方法访问时间越长,说明cpu占用越多。(其中百分比表示下面被上面被调用的可能性,ms表示时间,inv表示调用次数)。
方法统计:
程序线程监控:
创建线程dump:
/** * 功能演示测试 * @create 12:19 */ public class JProfilerTest { public static void main(String[] args) { while (true){ ArrayList list = new ArrayList(); for (int i = 0; i < 500; i++) { Data data = new Data(); list.add(data); } try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Data{ private int size = 10; private byte[] buffer = new byte[1024 * 1024];//1mb private String info = "hello,atguigu"; }
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]);//10kb beanList.add(data); } try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Bean { int size = 10; String info = "hello,atguigu"; // 注意是类变量 static ArrayList list = new ArrayList(); }
进入jprofiler,可以看到内存和类在不断变大,同时GC是正常执行的:
点击byte数组,分析heap walker:
查看都被谁引用了:
查看具体的引用关系:
可以看出byte[]来自于Bean类是的list中,并且这个list是ArrayList类型的静态集合,所以找到了:static ArrayList list = new ArrayList();发现list是静态的,这不妥,因为我们的目的是while结束之后Bean对象被回收,并且Bena对象中的所有字段都被回收,但是list是静态的,那就是类的,众所周知,类变量随类而生,随类而灭,因此每次我们往list中添加值,都是往同一个list中添加值,这会造成list不断增大,并且不能回收,所以最终会导致OOM。
建议本章节全部查看官方文档,不要看我写的。。。arthas官方文档
见官方文档:arthas官方文档
# 查看进程:
jps
#查看日志
cat ~/logs/arthas/arthas.log
#查看帮助
java -jar arthas-boot.jar -h
# 退出:
quit\exit
# 关闭:
stop\shutdown
可以看官方文档,建议直接查看官方文档。
dashboard:可以看到重复的数据有很多个,是因为每隔一段时间就会打印一次,可以通过dashboard -i 500
设置间隔500毫秒打印一次,同时可以设置dashboard -n 4
设置打印4次,可以dashboard -i 1000 -n 4
一起配置
thread:查看线程线程相关,可以thread id
查看具体线程信息,thread -b
查看死锁的情况,同样的也有thread -i 5000
查看5秒内cpu利用率,thread -n 2
查看cpu使用率前2的线程
sc:
sm:
jad:将class文件反编译成java文件
mc和redefine配合使用:
ClassLoader
jdk自带的分析工具:我看了下jdk8里面有,jdk11以后的版本没有了。
想要学习的可以自己看视频,这里不多说,视频子啊P359~P360
Flame Graphs火焰图
Tprofiler
Btrace
Yourkit
Hprobe
Spring Insight
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。