程序员

消除过期的对象引用

2017-07-06  本文已影响0人  DeppWang

你能看出以下代码哪里内存泄漏吗?

// 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);
    }
}

答案是:

pop()方法存在内存泄漏。

内存泄漏可以称为“ 无意识的对象保持(unintentional object retention)”。
在pop()方法中从栈中弹出来的对象将不会被当做垃圾回收。栈内部维护着对这些对象的过期引用(obsolete reference)。所谓的过期引用,是指永远也不会再被解除的引用。凡是在elements数组的“活动部分”(active portion)之外的任何引用都是过期的。活动部分是指elements中下标小于size的那些元素。

解决方法:上述述例子中的Stack类而言,只要一个单元被弹出栈,指向它的引用就过期了。一旦数组元素变成了非活动部分的一部分,就手工清空这些数组元素。修改后的pop()方法如下:

public Object pop() {
    if (size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];//result相当于一个temp。
    elements[size] = null; // Eliminate obsolete reference
    return result;
}

清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。

延伸阅读

length、size()、length()的区别:

前缀递减和后缀递增:

Arrays.copyOf()方法:

参考资料

上一篇下一篇

猜你喜欢

热点阅读