Effective Java笔记第一章创建和销毁对象

第六节消除过期的对象引用

关于内存泄漏方面可以看一下这篇文章内存泄漏,也许会对你理解这篇文章有些许帮助。

1.如果一个栈先增长,然后收缩,那么从栈中弹出的对象将不会被当做垃圾回收,即使使用栈的程序不再引用这些对象,他们也不会被回收。应为栈内部维护着对这些对象的过期引用。过期引用是指永远也不会再被解除的引用。

2.在支持垃圾回收的语言中,内存泄漏是很隐蔽的(我们称这类内存泄漏为"无意识的对象保持"更恰当)。如果一个对象引用被无意识的保留起来了,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的其他对象。

public class Demo1 {

    private Object[] elements;
    private int size=0;
    private static final int DEFAULT_INITIAL_CAPACITY=1;

    public Demo1(){
        elements=new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e){
        ensureCapacity();
        elements[size++]=e;
    }

    //未消除过期引用
//    public Object pop(){
//        if(size==0){
//            throw new EmptyStackException();
//        }
//        return elements[--size];
//    }

	  /**
     * 在本例中,凡是在element数组的"活动部分"之外的任何引用都是过期的,活动部分是指elements中下标小于size的那些元素
     * @return
     */
    //消除过期引用
    public Object pop(){
        if(size==0){
            throw new EmptyStackException();
        }
        //elements[--size]是对象,而result是这个对象的引用,相当于一个指针,也可以说是elements[--size]这个对象的地址。
        //对象是长生命周期的,而引用是短生命周期的。长生命周期的对象持有短生命周期的引用,就很可能出现内存泄漏
        Object result= elements[--size];
        //Eliminate obsolete reference  消除过时的引用
        elements[size]=null;
        return result;
    }

    //Ensure space for at least one more element ,roughly  至少确保还有一个元素空间
    //doubling the capacity each time the array needs to grow  每次阵列需要增长时,容量就增加一倍
    private void ensureCapacity(){
        if(elements.length==size){
            elements= Arrays.copyOf(elements,2*size+1);
        }
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
//        System.out.println(demo1.elements.length);
//        System.out.println(demo1.size);
        demo1.push(1);
//        System.out.println(demo1.elements.length);
//        System.out.println(demo1.size);
        demo1.push(2);
//        System.out.println(demo1.elements.length);
//        System.out.println(demo1.size);
        Object pop = demo1.pop();
        demo1.push(2);
//        System.out.println(pop);
        for (int i = 0; i < demo1.elements.length; i++) {
            System.out.println(demo1.elements[i]);
        }
    }

}

2.清空过期引用的另一个好处是,如果他们以后又会被错误的解除引用,程序就会立刻抛出NullPointException异常,而不是悄悄地错误运行下去。清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。

3.一般来说,只要类是自己管理内存,程序员就应该警惕内存泄露问题。内存泄漏还有另外两个常见的来源:1.缓存2.监听器和其他回调。