内存泄漏检测程序使用先进的图形表示技术,简化了复杂信息的浏览和理解。
那么,如何使用JRockit Memory Leak Detector 呢?
说明:本实验使用的JRockit Mission Control的版本为4.0.0。
1. 使用前的环境准备
(1)设置JAVA_HOME为JRockit所在目录。
(2)设置PATH=%JAVA_HOME%\bin;%PATH%
(3)运行 java -version 确认使用的JVM的确是 JRockit,以及具体版本。
(4)运行 java -Xpausetarget=30ms -Xverbose:gc DemoLeak。
(5)运行 启动 JAVA_HOME\bin\jrmc.exe。
(6)找到本地连接的Java程序DemoLeak,右键选择 Start Memleak。
2. 观察
JRockit Memory Leak Detector 有6个tab,分别是:
- 趋势
- 类型图形
- 类型树
- 实例图形
- 实例树
- 分配
趋势分析显示了Heap中最常见的对象类型、 对象类型的增长率、对象类型的实例数、所占内存大小 。趋势分析的运行时间越长,趋势就越可靠。
各个类型是按照增长速率的顺序排列的,我们最关注的当然是增长率最高的类型——这些类型很可能就是引起内存泄漏的类型。
可以看出,上图中增长率排在前三位的是:DemoLeak$DemoObject 、Hashtable$Entry 、Hashtable$Entry[] 。
到底是哪个对象类型引起了内存泄漏呢?仔细观察,我们发现DemoLeak$DemoObject 与Hashtable$Entry 实例数大致相当,因此我们可以推测Hashtable$Entry 中存放的就是DemoObject。
为了证实推测,右键点击DemoLeak$DemoObject ,选择“添加到类型图形”,看看有哪些类型指向了DemoObject。
在类型图形Tab中,我们展开指向DemoObject的所有节点,发现只有Hashtable$Entry——我们的猜测是对的!
继续展开指向Hashtable$Entry 的所有节点,发现只有Hashtable$Entry[]。右键Hashtable$Entry[],选择“列出最大数组”——因为最大的数组最可能引起内存泄露!
右键最大数组,选择“添加到实例图形”,发现有一个HashTable指向该数组。继续展开全部节点——有两个DemoThread 对象引用了该HashTable。
说明:本实验过程中断了一次,故最大数组新显示为12287,就是前面所指的393215。
右键其中一个DemoThread,选择“检查实例”。发现第一个参数是table,且指向该有问题的数组。
分析至此,我们基本找到问题的源头了——就是DemoThread.java中的table属性。剩下的工作就是分析该table属性,在哪个地方被不正确地使用了,最终导致了这个可疑的最大数组的产生。
3. DemoLeak.java
import java.util.Hashtable;
import java.util.List;
import java.util.ArrayList;
/*
* Copyright (c) 2007 by BEA Systems, Inc. All Rights Reserved.
*
* Created on 2003-dec-04
*/
/**
* Simple MemLeak demo
*/
public class DemoLeak {
private static class DemoObject {
private long position;
long myField1 = 1;
long myField2 = 2;
public DemoObject(int pos) {
position = pos;
}
public int hashCode() {
return (int)position;
}
public boolean equals(Object o) {
return (o instanceof DemoObject) && (o.hashCode() == position);
}
}
private static class AllocThread extends Thread {
public void run() {
while (true) {
List junkList = new ArrayList();
for (int i = 0; i < 1000; i++) {
junkList.add(new Object());
for (int j = 0; j < 10; j++)
Thread.yield(); // Keep busy yielding for a little while...
}
}
}
}
private static class DemoThread extends Thread {
private Hashtable table;
DemoThread(Hashtable h) {
table = h;
}
public void run() {
int total = 0;
while (true) {
for (int i = 0; i <= 100; i++)
put(total + i);
for (int i = 0; i < 100; i++)
remove(total + i);
total += 101;
for (int i = 0; i < 10; i++)
Thread.yield(); // Keep busy yielding for a little while...
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}
private void put(int n) {
table.put(new DemoObject(n), "foo");
}
private String remove(int n) {
return (String)table.remove(new DemoObject(n));
}
}
public static void main(String[] args) {
Hashtable h = new Hashtable();
Thread[] threads;
if (args.length != 1) {
threads = new Thread[2];
} else {
threads = new Thread[Integer.parseInt(args[0])];
}
for (int i = 0; i < threads.length; i++) {
threads[i] = new DemoThread(h);
threads[i].start();
}
new AllocThread().start();
}
}
没有评论:
发表评论