消除过期的对象引用

下面这段程序存在一个“内存泄漏”。在极端的情况下,会导致磁盘交换(Disk Paging),甚至导致程序失败(OutOfMemoryError)。
那么哪里引起的内存泄漏呢?
如果一个栈先是增长,然后再收缩,那么从栈中弹出来的对象讲不会被当做垃圾回收,即使使用的栈程序不再引用这些对象。
这是因为,栈内部维护着对这些对象的过期引用(obsolete reference)。过期引用是指,永远也不会再被接触的引用。
demo:

  1. // Can you spot the "memory leak"?  
  2.   
  3. import java.util.*;  
  4.   
  5. public class Stack {  
  6.     private Object[] elements;  
  7.     private int size = 0;  
  8.     private static final int DEFAULT_INITIAL_CAPACITY = 16;  
  9.   
  10.     public Stack() {  
  11.         elements = new Object[DEFAULT_INITIAL_CAPACITY];  
  12.     }  
  13.   
  14.     public void push(Object e) {  
  15.         ensureCapacity();  
  16.         elements[size++] = e;  
  17.     }  
  18.   
  19.     public Object pop() {  
  20.         if (size == 0)  
  21.             throw new EmptyStackException();  
  22.         return elements[--size];  
  23.     }  
  24.   
  25.     /** 
  26.      * Ensure space for at least one more element, roughly 
  27.      * doubling the capacity each time the array needs to grow. 
  28.      */  
  29.     private void ensureCapacity() {  
  30.         if (elements.length == size)  
  31.             elements = Arrays.copyOf(elements, 2 * size + 1);  
  32.     }  
  33. }  

修复的方法:
一旦对象引用已经过期,只需清空这些引用即可。
   

  1. public Object pop() {  
  2.     if (size == 0)  
  3.         throw new EmptyStackException();  
  4.     Object result = elements[--size];  
  5.     elements[size] = null//Eliminate obsolete reference     
  6.     return result;  
  7. }  


当然也没必要谨慎的将所有不用的东西设置为null。
清空对象引用应该是一种例外,而不是一种规范行为。
消除过期引用最好的方法是让包含该引用的变量结束其生命周期。
那么,合适应该清空引用呢?
问题在于,Stack类自己管理内存。存储池包含了elements数组的元素。数组活动区域中的元素是已分配的,而数组其余部分的元素则是自由的。
但是对于垃圾回收器而言,elements数组中的所有对象引用都同等有效。
一旦数组元素变成了非活动部分的一部分,程序员就收工清空这些数组元素。


只要类是自己管理内存,程序员就应该警惕内存泄漏问题。

内存泄漏的另一个常见来源是缓存。

LinkedHashMap类的removeEldestEntry(Map.Entry<K,V> eldest) 此方法非常有用:它允许映射通过删除旧条目来减少内存损耗。 

内存泄漏的第三个常见来源是监听器和其他回调。
如果你实现了一个API,客户端在这个API中注册回调,却没有显示的取消注册,那么除非你采取某些动作,否则他们就会积聚。
最佳方法是只保存他们的弱引用(weak reference),例如,只将他们保存为WeakHashMap中键。

可借助于Heap剖析工具(Heap Profiler)发现内存泄漏问题。

猜你喜欢

转载自windpoplar.iteye.com/blog/2315912