• 问题

    过期引用(obsolete reference)是指永远不会再被解除的引用,由于JVM有垃圾回收机制,如果存在过期引用,被引用的对象不会被回收掉,容易造成内存泄漏。那么,常见的内存泄漏有哪几种情况?

  • 解决

    1. 在使用Stack,List等“数据容器”的数据结构时,应该时刻关注容器中的数据元素是否有存在内存泄漏的情况,比如,下例中:

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

      如果一个stack先增后减,那么会弹出的对象并不会被当成垃圾回收,原因在于stack内部维持着对这些对象的过期引用(在这里是数组的原因),这样就造成了内存泄漏。因此,在弹出数据元素的时,最好是释放元素引用,如:

      Object obj = elements[--size];
      elements[size] = null
      
    2. 内存泄漏另一个常见来源是缓存:一旦把对象引用放到了缓存,当很长一段时间没有使用之后仍然存在于缓存之中。如果在缓存之外存在对某个数据项的键的引用的话,该缓存项才有意义。这样的场景是适合用WeakHashMap。

    3. 内存泄漏第三个常见来源是监听器和回调:如果注册了回调,并没有显式的进行注销,也会造成内存泄漏的问题。确保回调会被正常的垃圾回收,只需要保存他们的弱引用即可,例如,只将它们保存为WeakHashMap中的键。

  • 结论

    如果代码中存在过期引用,很容易造成内存泄漏,甚至会导致系统崩溃,在实际编码过程中需要仔细检查代码,或者借助于Heap工具去检查内存泄漏的问题。

results matching ""

    No results matching ""