高效Java06:消除过期的对象引用

类自己管理内存

一般而言,只要是类自己管理内存,我们就应该警惕内存泄漏问题。比如下面的例子:

public class Stack {
    private Object[] elements;
    private int size;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack(){
        elements = new Objects[DEFAULT_INITIAL_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);
        }
    }
}

上面的示例代码是一个简单的栈实现,并无明显的错误,无论怎样测试,它都能成功通过每一项测试,但是这里隐藏着一个问题:如果我们先进行入栈操作,然后在再进行出栈操作,从栈中弹出来的对象不会被当做垃圾回收。比如一个栈先进行入栈操作,至size的值为100,然后进行出栈操作至size的值为50,此时elements数组的活动部分为50,而另一部分已经出栈的50歌对象则为过期引用,且不会被回收,随着时间的推移,就有可能对性能造成潜在的重大影响。

这类问题的修复方法也很简单,即一旦对象引用过期,立即解除引用,本例中修正为:

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

缓存

另一个容易造成内存泄漏的来源是缓存,假设我们现在使用LinkedHashMap构建一个简单缓存,以维护要缓存的对象:

public class Cache extends LinkedHashMap {
    private static final Cache INSTANCE = new Cache();

    private Cache(){}

    public static Cache getInstance(){
        return INSTANCE;
    }
}

一旦我们把对象放入缓存,之后就很容易将他遗忘,随着时间的推移会变得越来越没有价值,这种情况下,我们应该将其清除。清除缓存可以由一个后台线程完成,或者在新加缓存数据时完成。示例代码中有则可以很容易实现第二种方案,LinkedHashMap中新加数据时会调用afterNodeInsertion(boolean)对最老的数据进行处理,是否清理则由removeEldestEntry(Map.Entry)的返回值决定,我们仅需覆盖该方法即可。


    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }

    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

监听器和其他回调

除了上面提到的内容,其他常见来源就是监听器和回调,如果注册了监听或回调,却没有显示的取消,它们就会不断累积,应当显示地取消注册。

总结:要及时消除过期的对象引用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值