第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修飾的變量,咱們應該把目光放在這些變量上。  生命週期

相關文章
相關標籤/搜索