GC算法基礎

GC算法:基礎篇

在深刻GC算法的實現細節以前,咱們最好先來了解下相關術語及背後的基本原理。不一樣回收器的實現細節各有不一樣,但總的來講基本全部的回收器都會關注以下兩個方面:html

  • 找出全部的存活對象
  • 清理掉全部的其它對象——也就是那些被認爲是廢棄或無用的對象。

首先,全部回收器都會經過一個標記過程來對存活對象進行統計。算法

標記可達對象

JVM中用到的全部現代GC算法在回收前都會先找出全部仍存活的對象。下圖中所展現的JVM中的內存佈局能夠用來很好地闡釋這一律念:安全

首先,垃圾回收器將某些特殊的對象定義爲GC根對象。所謂的GC根對象包括:佈局

  • 當前執行方法中的全部本地變量及入參
  • 活躍線程
  • 已加載類中的靜態變量
  • JNI引用

接下來,垃圾回收器會對內存中的整個對象圖進行遍歷,它先從GC根對象開始,而後是根對象引用的其它對象,好比實例變量。回收器將訪問到的全部對象都標記爲存活。spa

存活對象在上圖中被標記爲藍色。當標記階段完成了以後,全部的存活對象都已經被標記完了。其它的那些(上圖中灰色的那些)也就是GC根對象不可達的對象,也就是說你的應用不會再用到它們了。這些就是垃圾對象,回收器將會在接下來的階段中清除它們。線程

關於標記階段有幾個關鍵點是值得注意的:指針

  • 開始進行標記前,須要先暫停應用線程,不然若是對象圖一直在變化的話是沒法真正去遍歷它的。暫停應用線程以便JVM能夠盡情地收拾家務的這種狀況又被稱之爲安全點(Safe Point),這會觸發一次Stop The World(STW)暫停。觸發安全點的緣由有許多,但最多見的應該就是垃圾回收了。
  • 暫停時間的長短並不取決於堆內對象的多少也不是堆的大小,而是存活對象的多少。所以,調高堆的大小並不會影響到標記階段的時間長短。

當標記階段完成後,GC開始進入下一階段,刪除不可達對象。htm

刪除無用對象

不一樣的GC算法在刪除無用對象上的作法會有所不一樣,不過大體上能夠爲分三類:清除(Sweeping),整理/壓縮(Compacting)以及拷貝(Copying)。下面的幾節將會詳細介紹下這幾種算法的不一樣。對象

清除內存

從概念上來說,標記-清除算法使用的方法是最簡單的,只須要忽略這些對象即可以了。也就是說當標記階段完成以後,未被訪問到的對象所在的空間都會被認爲是空閒的,能夠用來建立新的對象。

這種方法須要使用一個空閒列表來記錄全部的空閒區域以及大小。對空閒列表的管理會增長分配對象時的工做量。這種方法還有一個缺陷就是——雖然空閒區域的大小是足夠的,但卻可能沒有一個單一區域可以知足此次分配所需的大小,所以本次分配仍是會失敗(在Java中就是一次OutOfMemoryError)。

整理

標記-清除-整理算法修復了標記-清除算法的短板——它將全部標記的也就是存活的對象都移動到內存區域的開始位置。這種方法的缺點就是GC暫停的時間會增加,由於你須要將全部的對象都拷貝到一個新的地方,還得更新它們的引用地址。相對於標記-清除算法,它的優勢也是顯而易見的——通過整理以後,新對象的分配只須要經過指針碰撞便能完成(pointer bumping),至關簡單。使用這種方法空閒區域的位置是始終可知的,也不會再有碎片的問題了。

複製

標記-複製算法與標記-整理算法很是相似,它們都會將全部存活對象從新進行分配。區別在於從新分配的目標地址不一樣,複製算法是爲存活對象分配了另外的內存區域做爲它們的新家。標記複製算法的優勢在於標記階段和複製階段能夠同時進行。它的缺點是須要一塊能容納下全部存活對象的額外的內存空間。

原創文章轉載請註明出處:GC算法基礎

相關文章
相關標籤/搜索