初始代码
/**
* 泛型栈
* @author 焦焱
*
* @param <T>
*/
public class TStack<T> {
/**
* 泛型数组
*/
private T[] data = null;
/**
* 栈顶
*/
private int top;
/**
* 栈的长度
*/
private int length;
/**
* 空构造函数
*/
public TStack() {
this(10);
}
/**
* 有参构造函数
* @param i 栈的长度
*/
public TStack(int i)
{
//data = new T[i]; × 错误
length = i;
//通过将object数组强转为泛型数组的方式创造泛型数组
data = (T[]) new Object[length];
//栈顶初始化
top = 0;
}
/**
* 入栈
* @param val
*/
public void push(T val)
{
if(top>=length)
{
return;
}
this.data[top++] = val;
}
/**
* 出栈
* @return 数据
*/
public T pop()
{
if(top==0)
{
return null;
}
T a = this.data[--top];
//稍后在此插入代码
return a;
}
/**
* 获得栈顶元素
* @return 数据
*/
public T getTop()
{ if(top==0)
{
return null;
}
return this.data[top-1];
}
public static void main(String[] args) {
TStack<User> a = new TStack<User>(10);
for (int i = 0; i < a.length; i++) {
a.push(new User("1", "1", i));
}
System.out.println(a.pop());
//手动调用gc
System.gc();
//断点打在此
System.out.println();
}
}
打断点后进行调试
然后打开cmd
输入
jps
可以看到
可以看到进程号
然后我们将此进程中的运行信息导入到一个txt文件中
执行
jmap -histo:live 72276 >log.txt
然后在你自己的用户路径下找文件
查找到以后打开
可以看到
这就是当时运行的时候jvm中所运行的java对象
在里面找到User对象。
然后在留的//稍后在此插入代码
这一行插入
this.data[top] = null;
及释放对象,重复进行以上操作
打开log.txt
我们发现User对象变成了9
总结
所以我们第一次写的代码是有内存泄露的,因为当我们pop出去一个User之后,它并没有消失,而是还在被引用,所以会占用JVM的内存空间,这样的代码是不好的,所以我们看到的实例数为10。
当我们加入哪一行之后,pop出去以后,当前User的引用会被置为null,相应堆内的User也会等待回收,当我们手动gc后就会被回收掉,所以实例数会变为9。