import java.util.Arrays; public class Stack { private static final int INIT_SIZE = 10; private Object[] datas; private int size; public Stack() { super(); datas = new Object[INIT_SIZE]; } public void push(Object data){ if (size == datas.length) { extend(); } datas[size++] = data; } public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } return datas[--size]; } private void extend(){ datas = Arrays.copyOf(datas, 2 * size + 1); } }
上述代码,是从其他博客拷贝过来的。
上述代码的意思:
1.入栈,将指向某个对象的引用值,存放进来。
2.出栈,将指向某个对象的引用值,返回给用户。
潜在的问题:
public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } return datas[--size]; }
这段代码的含义是,返回指向某个对象的引用值,然后,将栈顶向下移动。虽然是返回了某个对象的引用值,但是,数组中依然还保留着被返回的对象的引用值。这样的话,如果没有再进行入栈操作(用指向新的对象的引用值覆盖掉),那么,数组中就依然保留着被返回对象的引用值。
而用户会觉得,既然某个对象已经出栈了,那么,该对象就不会还在栈中。而实际上,该对象还是在的,因为,datas数组中依然保留着指向该对象的引用值。如此,如果用户不再使用Stack进行入栈操作,那么,Stack就会一直保留着指向该对象的引用值。
从而,也就出现了内存泄漏。对象依然存在在堆中,但用户并不知道,也不知道如何通过引用使用它。
解决办法:每次返回某个指向对象的引用时,顺便将数组中保留的引用值置空,这样数组中就没有保存返回的对象引用值了。这样,GC在进行回时,就可以将该对象从堆中移除。
public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } Object data = datas[--size]; datas[size] = null; return data; }
下面用具体例子展示:
这样执行之后,用户以为stack中,已经没有指向a对象的引用了,实际上,还是有的。所以,堆上依然保留着a对象。
public static void main(String[] args) { Object a = new Object(); Stack stack = new Stack(); stack.push(a); stack.pop(); a = null; }
指向对象的引用置空---与内存泄漏
时间: 2024-10-10 08:20:52