1、jdk工具之jps(JVM Process Status Tools)命令使用html
2、jdk命令之javah命令(C Header and Stub File Generator)java
3、jdk工具之jstack(Java Stack Trace)算法
4、jdk工具之jstat命令(Java Virtual Machine Statistics Monitoring Tool)缓存
4、jdk工具之jstat命令2(Java Virtual Machine Statistics Monitoring Tool)详解app
5、jdk工具之jmap(java memory map)、 mat之四--结合mat对内存泄露的分析eclipse
6、jdk工具之jinfo命令(Java Configuration Info)jvm
7、jdk工具之jconsole命令(Java Monitoring and Management Console)工具
8、jdk工具之JvisualVM、JvisualVM之二--Java程序性能分析工具Java VisualVMpost
9、jdk工具之jhat命令(Java Heap Analyse Tool)性能
10、jdk工具之Jdb命令(The Java Debugger)
11、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)
11、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)
12、jdk工具之jcmd介绍(堆转储、堆分析、获取系统信息、查看堆外内存)
十3、jdk命令之Java内存之本地内存分析神器:NMT 和 pmap
打印出某个java进程(使用pid)内存内的,全部‘对象’的状况(如:产生那些对象,及其数量)。
能够输出全部内存中对象的工具,甚至能够将VM 中的heap,以二进制输出成文本。使用方法 jmap -histo pid。若是连用SHELL jmap -histo pid>a.log能够将其保存到文本中去,在一段时间后,使用文本对比工具,能够对比出GC回收了哪些对象。jmap -dump:format=b,file=outfile 3024能够将3024进程的内存heap输出出来到outfile文件里,再配合MAT(内存分析工具(Memory Analysis Tool),使用参见:http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)或与jhat (Java Heap Analysis Tool)一块儿使用,可以以图像的形式直观的展现当前内存是否有问题。
查看该进程(pid)下堆内存的使用状况:
jmap -heap pid
快速定位内存泄漏的方法:只统计存活的对象
jmap -histo:live pid
还能够导出:
jmap -histo:live pid >1.txt将信息输出到指定文件中
SYNOPSIS
jmap [ option ] pid
jmap [ option ] executable core
jmap [ option ] [server-id@]remote-hostname-or-IP
1)、options:
executable Java executable from which the core dump was produced.
(多是产生core dump的java可执行程序)
core 将被打印信息的core dump文件
remote-hostname-or-IP 远程debug服务的主机名或ip
server-id 惟一id,假如一台主机上多个远程debug服务
2)、基本参数:
-dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
-finalizerinfo 打印正等候回收的对象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用状况.
-histo[:live] 打印每一个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 若是live子参数加上后,只统计活的对象数量.
-permstat 打印classload和jvm heap长久层的信息. 包含每一个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来.
-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效.
-h | -help 打印辅助信息
-J 传递参数给jmap启动的jvm.
pid 须要被打印配相信息的java进程id,创业与打工的区别 - 博文预览,能够用jps查问.
tasklist命令查看进程id(Tasklist"是 winxp/win2003/vista/win7/win8下的命令,用来显示运行在本地或远程计算机上的全部进程,带有多个执行参数。)
经常使用的参数以下:
histo
jmap -histo pid 展现class的内存状况
展现的信息为编号,实例数,字节,类名
-finalizerinfo
打印等待回收的对象信息
jmap -finalizerinfo 4783 Attaching to process ID 4783, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.171-b11 Number of objects pending for finalization: 0 [root@ip-172-29-206-104 applogs]#
heap
jmap -heap pid 展现pid的总体堆信息
jmap -heap 2464 JVM version is 16.3-b01 using thread-local object allocation. Parallel GC with 13 thread(s) Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 8436842496 (8046.0MB) NewSize = 5439488 (5.1875MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 88080384 (84.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 87883776 (83.8125MB) used = 31053080 (29.614524841308594MB) free = 56830696 (54.197975158691406MB) 35.33425782706469% used From Space: capacity = 13828096 (13.1875MB) used = 196608 (0.1875MB) free = 13631488 (13.0MB) 1.4218009478672986% used To Space: capacity = 16384000 (15.625MB) used = 0 (0.0MB) free = 16384000 (15.625MB) 0.0% used PS Old Generation capacity = 156172288 (148.9375MB) used = 27098208 (25.842864990234375MB) free = 129074080 (123.09463500976562MB) 17.35148299805917% used PS Perm Generation capacity = 88080384 (84.0MB) used = 50847592 (48.492042541503906MB) free = 37232792 (35.507957458496094MB) 57.728622073218936% used
说明以下
Parallel GC with 13 thread(s) #13个gc线程 Heap Configuration:#堆内存初始化配置 MinHeapFreeRatio = 40 #-XX:MinHeapFreeRatio设置JVM堆最小空闲比率 MaxHeapFreeRatio = 70 #-XX:MaxHeapFreeRatio设置JVM堆最大空闲比率 MaxHeapSize = 8436842496 (8046.0MB)#-XX:MaxHeapSize=设置JVM堆的最大大小 NewSize = 5439488 (5.1875MB) #-XX:NewSize=设置JVM堆的‘新生代’的默认大小 MaxNewSize = 17592186044415 MB #-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小 OldSize = 5439488 (5.1875MB) #-XX:OldSize=设置JVM堆的‘老生代’的大小 NewRatio = 2 #-XX:NewRatio=:‘新生代’和‘老生代’的大小比率 SurvivorRatio = 8 #-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值 PermSize = 21757952 (20.75MB) #-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小 MaxPermSize = 88080384 (84.0MB) #-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小 Heap Usage: PS Young Generation Eden Space:#Eden区内存分布 capacity = 87883776 (83.8125MB) used = 31053080 (29.614524841308594MB) free = 56830696 (54.197975158691406MB) 35.33425782706469% used From Space:#其中一个Survivor区的内存分布 capacity = 13828096 (13.1875MB) used = 196608 (0.1875MB) free = 13631488 (13.0MB) 1.4218009478672986% used To Space:#另外一个Survivor区的内存分布 capacity = 16384000 (15.625MB) used = 0 (0.0MB) free = 16384000 (15.625MB) 0.0% used PS Old Generation#当前的Old区内存分布 capacity = 156172288 (148.9375MB) used = 27098208 (25.842864990234375MB) free = 129074080 (123.09463500976562MB) 17.35148299805917% used PS Perm Generation#当前的 “永生代” 内存分布 capacity = 88080384 (84.0MB) used = 50847592 (48.492042541503906MB) free = 37232792 (35.507957458496094MB) 57.728622073218936% used
mat为eclipse的一个内存分析插件,帮助查找内存泄漏和减小内存消耗。
首先基于jmap导出的堆信息
jmap -dump:live,format=b,file=test.bin 29030
准备代码:
class User { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User(String id, String name) { super(); this.id = id; this.name = name; } }
main方法:
public static void main(String[] args) { List<User> list = new ArrayList<User>(); for (int i = 1; i < 10000; i++) { User o = new User(i + "", System.currentTimeMillis() + ""); list.add(o); o = null; } System.out.println("end"); try { Thread.sleep(100000000l); } catch (InterruptedException e) { e.printStackTrace(); } }
执行以后用jmap输出堆信息
而后导入分析工具
咱们能够看到图形化展现:
而后咱们点击
以下所示:
而后点击详情
咱们能够看到有不少的User对象
这些对象有可能会溢出,而后咱们打开OQL窗口看他是否为null,执行以下OQL语句
SELECT u FROM org.learn.util.User u WHERE (u.value = null)
也就是说这个是null,可是仍然有强引用存在,gc的时候是不能回收的,这样就会出现内存的溢出问题
我用MAT打开了heap.bin,很容易看出,char[]的数量出其意料的多,占用90%以上的内存 。通常来讲,char[]在JVM确实会占用不少内存,数量也很是多,由于String对象以char[]做为内部存储。可是此次的char[]太贪婪 了,仔细一观察,发现有数万计的char[],每一个都占用数百K的内存 。这个现象说明,Java程序保存了数以万计的大String对象 。结合程序的逻辑,这个是不该该的,确定在某个地方出了问题。
在可疑的char[]中,任意挑了一个,使用Path To GC Root功能,找到该char[]的引用路径,发现String对象是被一个HashMap中引用的 。这个也是意料中的事情,Java的内存泄露多半是由于对象被遗留在全局的HashMap中得不到释放。不过,该HashMap被用做一个缓存,设置了缓 存条目的阈值,导达到阈值后会自动淘汰。从这个逻辑分析,应该不会出现内存泄露的。虽然缓存中的String对象已经达到数万计,但仍然没有达到预先设置 的阈值(阈值设置地比较大,由于当时预估String对象都比较小)。
可是,另外一个问题引发了个人注意:为何缓存的String对象如此巨大?内部char[]的长度达数百K。虽然缓存中的 String对象数量尚未达到阈值,可是String对象大小远远超出了咱们的预期,最终致使内存被大量消耗,造成内存泄露的迹象(准确说应该是内存消 耗过多) 。
就这个问题进一步顺藤摸瓜,看看String大对象是如何被放到HashMap中的。经过查看程序的源代码,我发现,确实有String大对象,不 过并无把String大对象放到HashMap中,而是把String大对象进行split(调用String.split方法),而后将split出 来的String小对象放到HashMap中 了。
这就奇怪了,放到HashMap中明明是split以后的String小对象,怎么会占用那么大空间呢?难道是String类的split方法有问题?