第6条:消除过时的对象引用

  虽然当咱们用完对象后,java有垃圾回收机制进行回收,可是并无那么的智能,对于某些被引用的对象,就算咱们已经不在使用它了,可是java的回收机制是不会回收他们的,人们称之为“内存泄漏”。java

  不少时候内存泄漏都是“人们无心识的内存引用”形成的,举个简单的例子:数组

List<String> list = new ArrayList<>();
String str = "testString";
list.add(str);
str  = null;

  看似上面的str被回收了,可是,事实上建立str时所开辟的内存空间是不会被回收的,由于list依然持有对str的引用这就是一个典型的“无心识的内存引用”。为了防止这些“无心识的内存引用”,咱们应该了解对象相互引用的时候是存在怎样的依赖关系的。spa

  下面咱们在看看一个简单的栈实现例子:code

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

    private void ensureCapacity(){
        if(elements.length == size){
            elements = Arrays.copyOf(elements,2*size+1);
        }
    }
  
  public Object pop(){
    if(size == 0){
      throw new EmptyStackException();
    }
    Object result = elements[--size];
    return result;
  }
}

  看似这段程序没有明显的错误,也能运行,可是这里面存在一个内存泄漏问题,若是栈先增加了,而后在收缩,那么栈中弹出的对象将不被当作垃圾回收,即便使用栈的程序不在引用这些对象了,它们也不会被回收,由于栈内部维护着对这些对象的过时引用,所谓的过时引用是指永远不在会被解除的引用,这里就是凡在elements数组的活动部分以外的任何引用都是过时的。对象

  对于上述这些修复的方法仍是比较简单的,一旦对象是过时引用,只须要清空这些引用便可,对应上述例子中的Stack而已,只要一个单元被弹出栈,那就是过时引用,只须要在pop方法的return result上面加上elements[size] = null;便可。blog

  固然,咱们不要由于惧怕内存泄漏而在全部的地方都手动回收内存,这样会致使咱们的代码凌乱臃肿,不利于管理,咱们应该把目标集中在那些长声明周期的变量中,哪些是长生命周期的变量呢,最明显的一个就是static修饰的变量,咱们应该把目光放在这些变量上。  生命周期

相关文章
相关标签/搜索