條款7:消除廢棄的對(duì)象引用(一)

條款7:消除廢棄的對(duì)象引用(一)

如果你從??需要?動(dòng)進(jìn)?內(nèi)存管理的語?(如C或是C++)轉(zhuǎn)到了垃圾回收語?(如Java),那么作為程序員來說,你的?作會(huì)簡(jiǎn)化很多,因?yàn)閷?duì)象在被使?完畢后會(huì)?動(dòng)回收。在初次經(jīng)歷這個(gè)事情時(shí),?切感覺都像夢(mèng)幻?樣。這很容易會(huì)讓你覺得不需要考慮內(nèi)存管理問題,不過事實(shí)卻并?如此。

考慮如下簡(jiǎn)單的棧實(shí)現(xiàn)代碼:

public class Stack {

  private Object[] elements;
  private int size = 0;
  /*棧初始容量大小*/
  private static final int DEFAULT_INITIAL_CAPACITY = 16;

  /*構(gòu)造方法,初始化數(shù)組*/
  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];
  }

  /**
    * 確保當(dāng)棧滿時(shí),擴(kuò)展容量為原來的一倍
   */
  private void ensureCapacity() {
    if (elements.length == size) {
      elements = Arrays.copyOf(elements, 2 * size + 1);
    }
  }
}

上述程序并沒有明顯的錯(cuò)誤(不過請(qǐng)查看條款29來了解更加通?的版本)。你可以不斷測(cè)試該程序,程序也會(huì)順利通過每個(gè)測(cè)試,不過有?個(gè)潛伏的問題。?致來說,該程序存在?處『內(nèi)存泄露』,其性能會(huì)逐步降低,這是因?yàn)椴粩嘣黾拥睦占骰顒?dòng)與內(nèi)存占?問題。在極端情況下,這種內(nèi)存泄露會(huì)導(dǎo)致磁盤分?,甚?會(huì)因OutOfMemoryError造成程序失敗,不過這種失敗的情況是?常少?的。

那么內(nèi)存泄露出現(xiàn)在什么地?呢?如果棧不斷增?,然后再收縮,那么從棧中彈出的對(duì)象就不會(huì)被垃圾回收掉,即便使?了棧的程序不再引?他們亦如此。這是因?yàn)闂>S護(hù)了對(duì)這些對(duì)象的廢棄的引?。廢棄的引?指的是永遠(yuǎn)不會(huì)被解引?的引?。在該示例中,位于元素?cái)?shù)組『活動(dòng)部分』之外的任何引?都是廢棄的?;顒?dòng)部分包含了索引?于size的元素。

垃圾收集語?中的內(nèi)存泄露(更恰當(dāng)?shù)慕蟹ㄊ?strong>?意的對(duì)象保持)是?常不易察覺的。如果對(duì)象引?被?意保持了,那么不僅該對(duì)象會(huì)從垃圾收集中排除出去,該對(duì)象所引?的其他對(duì)象也會(huì)被排除出去,以此類推。即便只有少量的對(duì)象引?被?意保持了,造成的后果就是會(huì)有很多、很多對(duì)象會(huì)從垃圾收集中排除出去,這會(huì)對(duì)性能造成很嚴(yán)重的影響。

這類問題的解決?案很簡(jiǎn)單:?旦引?變成廢棄狀態(tài),?刻將其置為null。對(duì)于我們的Stack類來說,如果元素從棧中彈出,那么對(duì)其的引?就變成廢棄狀態(tài)了。pop?法的正確版本如下代碼所示:

public Object pop() {
  if (size == 0) {
    throw new EmptyStackException();
  }
  Object result = elements[--size];
  //置空,強(qiáng)制讓GC去回收廢棄的引用對(duì)象
  elements[size] = null; 
  return result;
}

將廢棄引?置為null的另?個(gè)好處在于,如果他們隨后被錯(cuò)誤地解引?了,那么程序就會(huì)?刻失敗,并拋出NullPointerException異常,?不是安靜地做錯(cuò)誤的事情。盡可能快地檢測(cè)程序錯(cuò)誤終歸是有好處的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容