内存泄露是一个很不容易发现的问题,在不少状况下,咱们都很容易忽略,Java的垃圾回收确实帮助咱们解决了很多内存管理的问题,可是,这并不意味着咱们就能够彻底依赖Java的垃圾回收。咱们仍是在编写程序的时候须要考虑内存管理的问题。下面咱们先来看一个例子,java
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); }
可是这个程序中隐藏着一个问题。不严格地讲,这段程序有一个"内存泄漏(Memory Leak)",随着垃圾回收器活动的增长,或者因为内存占用的不断增长,程序性能的下降会逐渐表现出来。若是一个栈先是增加,而后再收缩,那么,从栈中弹出来的对象将不会被看成垃圾回收,即便使用栈的程序再也不引用这些对象,它们也不会被回收。这是由于,栈内部维护着对这些对象的过时引用(obsolete reference)。所谓的过时引用,是指永远也不会再被解除的引用。程序员
这类问题的修复方法很简单:一旦对象引用已通过期,只需清空这些引用便可。对于上述例子中的Stack类而言,只要一个单元被弹出栈,指向它的引用就过时了。pop方法的修订版本以下所示:缓存
public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; }
通常而言,只要类是本身管理内存,程序员就应该警戒内存泄漏问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。性能
内内存泄露的另外一个常见来源是缓存,所以这时要用一个线程按期清缓存或在加入时清最少使用的缓存对象。在1.4发行版中,能够用java.util.LinkedHashMap的revmoveEldestEntry方法来实现后一方案。
spa