本文将简单介绍工具Eclipse Memory Analyzer以及如何使用此工具查找一些内存问题。
一. 将内存分析器安装到Eclipse中
启动更新管理通过帮助→软件更新…
选择“可用软件”选项卡并添加内存分析器更新站点:http://download.eclipse.org/technology/mat/0.7/update-site/
选择内存分析器功能。点击“安装”按钮进行安装。
接受许可证并重新启动Eclipse(也可以作为单独的软件直接使用)
二. 从JVM虚拟机获取堆转储dump文件
内存分析器可以处理HPROF二进制格式的堆转储。这些堆转储由Sun HotSpot和从HotSpot派生的任何VM编写。根据您的场景、操作系统平台和JDK版本,您可以使用不同的选项来获取堆转储。
Vendor / Release | -XX:+HeapDumpOnOutOfMemoryError writes heap dump on OutOfMemoryError | -XX:+HeapDumpOnCtrlBreak writes heap dump together with thread dump on CTRL+BREAK | Sun JMap: jmap.exe -dump:format=b,file=HeapDump.hprof | Sun JConsole: Launch jconsole.exe and invoke operation dumpHeap() on HotSpotDiagnostic MBean |
1.4.2_12 | Yes | Yes | No | No |
1.5.0_07 | Yes | No | Yes(Only Solaris and Linux) | No |
1.6.0_00 | Yes | No | Yes | Yes |
一般情况下,堆转储dump文件将生成为java_pid3524.hprof
三. 查找内存泄漏的最简单方法
Eclipse菜单窗口→打开透视图→内存分析器
Eclipse菜单文件→打开堆转储=>选择hprof文件,如java_pid3524.hprof
将显示概览图:
单击“Leak Suspects”报告链接
单击问题 Suspect 1 Details 链接
然后你会看到:
Class name | Shallow Heap | Retained Heap | Percentage |
java.lang.Object@ 0×23d04040 | 9,047,792 | 273,923,024 | 97.00% |
com.starcite.commonsearch.client.vendor.impl.VendorImpl @ 0×16b80000 | 135 | 136 | 0.00% |
所以java.lang.Object2261945@0×23d04040“大约需要9M的浅堆(这意味着直接引用的内存)和273m的保留堆(这意味着直接引用或不直接引用的所有内存)。现在,我们可以知道这是内存泄漏的根本原因。
那么,接下来呢?当然,下一步是找出导致此问题的代码?
然而,这不是一件容易的事。你现在必须利用你的经验。
有什么信息可以作为出发点吗?您可以找到以下信息-
Accumulated Objects "堆积物"
Class name | Shallow Heap | Retained Heap | Percentage |
java.lang.Thread @ 0×18ff9320 http-8080-1 | 88 | 273,945,736 | 97.01% |
java.util.ArrayList @ 0×18ff93a0 | 24 | 273,923,048 | 97.00% |
java.lang.Object261945@ 0×23d04040 | 9,047,792 | 273,923,024 | 97.00% |
com.starcite.commonsearch.client.vendor.impl.VendorImpl @ 0×16b80000 | 135 | 136 | 0.00% |
从这个角度来看,内存是由java.lang.Thread线程@0×18ff9320 http-8080-1。因此,它应该发生在一个HTTP请求中。
然后,在thread details部分中找到这个线程。然后单击线程属性链接。请看:
现在您可能会找到一些提示,例如vendorsearchmeditor
、SearchVendorByIDsInput
等。根据这些信息,您可能会找到根代码:
public SearchVendorByIDsOutput searchVendorByIDs(SearchVendorByIDsInput input) {
List<vendor> vendors = new ArrayList</vendor><vendor>();
for (;;) {
VendorImpl v = new VendorImpl();
v.setName("name");
vendors.add(v);
}
}
</vendor>
四. 如何找到占用内存的未使用集合–强大的对象查询语言OQL
在开发过程中,您可能永远不会注意到大量已实例化但从未使用过的集合。
默认容量为10的空ArrayList
在32位系统上花费80字节,在64位系统上花费144字节。
如果在我们的应用程序中通常使用MyValueStorage
类,并且堆中有它的500.000个实例,那么在32位系统上(64位–144MB)将为specialValues和errors values列表保留80Mb。但只需要5%左右。因此,对这两个字段使用延迟初始化可能是一个好主意(在实际使用之前保持它们为null)。我们要付出的代价是几个“if
”语句,以避免遇到NullPointerExceptions。
打开对象查询语言Studio以执行语句
有关OQL语法的详细说明,请查看帮助页。目前我们只需要几个具体的问题。对于查找enpty和未修改的ArrayLists
、HashMaps
和Hashtables
,它们如下所示:
select * from java.util.ArrayList where size=0 and modCount=0
select * from java.util.HashMap where size=0 and modCount=0
select * from java.util.Hashtable where count=0 and modCount=0
然后你可以得到每个项目的保留堆,比如80字节。总共有857个条目。所以,它们不会占用太多的内存。
五. VendorImpl使用了多少内存–强大的对象查询语言
打开对象查询语言Studio以执行语句
运行以下OQL:
select * from com.starcite.commonsearch.client.vendor.impl.VendorImpl
点击“显示直方图”你会发现VendorImpl的耗费超过260M内存,这很特别。
总之,Eclipse内存分析器是一个非常强大的内存分析器工具。而且更容易发现潜在的内存泄漏。您还可以找到任何java对象所使用的内存。
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1326.html
暂无评论