Item 6 Eliminate obsolete object references

虽然Java有垃圾回收功能,但有时候还是要手动回收过期对象引用。

内存泄露第一个常见来源

比如,下面这段代码存在内存泄露。

// Can you spot the "memory leak"?
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    public Stack() {
        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];
    }
    /**
     * 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);
    }
}
复制代码

So where is the memory leak? If a stack grows and then shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them. 一个堆栈push之后又pop,增大后又收缩,这样弹出的object不会被垃圾回收。 正确做法:

public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
复制代码

这有点颠覆我的观念了。因为我很少有人用完array之后把无效的元素赋值成null的。 比如DFS中常用的backtracking常常会缩小array:

stringBuilder.deleteCharAt(sb.length() - 1);
//或者
arrayList.remove(arrayList.size() - 1);
复制代码

但从没见过有人会把弹出的那个最后的元素解除引用啊。。 于是书里又说,Nulling out object references should be the exception rather than the norm. 清空引用是例外而不是常态。 对GC来说数组中所有对象引用都有效,但我们知道size之外的已经没用了所以要手动回收。

我在网上看到一个例子,如何手写一个例子让编译器提示outOfMemory?这样做:

public class OutOfMemoryTest {
    public static void main(String[] args){
        List list=new ArrayList();
        for(;;){
            int[] tmp=new int[1000000];
            list.add(tmp);
        }
    }
}
复制代码

另外提一下,

  1. Arrays.copyOf会截取或者扩大一个array。扩大的新array后面会填充null。
  2. main函数的String args[] 的args就像命令行中加入的额外参数。

内存泄露第二个常见来源

缓存。放到缓存中的对象引用容易被遗忘。可以用WeakHashMap。

内存泄露第三个常见来源

监听器和其他回调。解决方法是用WeakReference。 这个我记得很久以前写过register和deregister接口,但忘了啥意思了。。

转载于:https://juejin.im/post/5a313405f265da43346fea39

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值