代码改变世界

指向对象的引用置空---与内存泄漏

2014-08-02 11:06  ttylinux  阅读(855)  评论(0编辑  收藏  举报
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;

}