Effective Jave 创建和销毁对象 6.消除过期的对象应用

来源:互联网 发布:优化蜜蜡好吗 编辑:程序博客网 时间:2024/06/18 12:41
在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。但是却不代表我们不需要考虑内存管理的事情。


public class Stack {
    pprivate Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITAL_CAPACITY = 16;
    
    public Stack() {
        elements = new Object[DEFAULT_INITAL_CAPACITY];
    }
    
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    
    public Object pop() {
        if(size == 0) {
            throw new EmptyStackException();
        }
        return elements[--size];
    }
    
    private void ensureCapacity() {
        if(elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}


这段程序没有任何明显的错误,无论如何测试,他都会成功的通过每一项测试,但这个程序中隐藏着一个问题,不严格的将,这个程序会导致内存泄漏。
随着垃圾回收器活动的增加或者由于内存占用的不断增加,程序的性能不断降低,在极端的情况下,甚至会导致OOM,但OOM还是比较少见。


那么程序中哪里发生了OOM呢?如果一个栈先是增长,然后收缩,那么从栈中弹出来的对象不会被当作垃圾回收,
这是因为栈内部仍然维护着这些过期对象的引用,所谓过期引用是指elements中下标大于等于size的那些元素(由于栈会增长收缩,所以这是完全有可能的),如果一个对象被无意识地(即我们不希望地)保留下来,那么这个引用所引用的其他对象也不会被垃圾回收机制回收,因为仍然存在着引用,GC认为这些对象仍然是会被使用的。随着程序的运行时间增长,过期的对象引用占用的内存会越来越大,导致程序性能下降。


 


这类问题的解决方法是:一旦对象引用已经过期,只需清空这些引用即可。


public Object pop() {
        if(size == 0) {
            throw new EmptyStackException();
        }
        Object result = elements[--size];
        elements[size] = null;
        return result;
}


清空过期引用的另一和好处就是,如果它们以后又被错误的解除引用,程序会立即抛出空指针异常,而不是悄悄的运行下去。


当我们被类似的问题坑过后,就会过分的小心,对于每个应用对象一旦不再使用,立马清空。其实这样做是没有必要的,也不是我们期望的,这样会导致代码很乱。--清空一个对象引用只是个例,而不是规范行为。清空过期引用的最好方法就是让对象本身结束生命周期。
阅读全文
2 0
原创粉丝点击