工作原理:為每個內存對象維護一個引用計數。
當有新的引用指向某對象時就將該對象的引用計數加一,當指向該對象的引用被銷毀時將該計數減一,當計數歸零時,就回收該對象所占用的內存資源。
缺陷:在每次內存對象被引用或引用被銷毀的時候都必須修改引用計數,這類操作被稱為footprint。引用計數的footprint是很高的。這使得程序整體的性能受到比較大的影響。因此多數現代的程序語言都不適用引用計數作為垃圾收集的實現算法。
另外,引用計數還有一個致命的缺陷,當程中出現序循環引用時,引用計數算法無法檢測出來,被循環引用的內存對象就成了無法回收的內存。從而引起內存泄露。
舉例說明就是:
class A{ public B b; } class B{ public A a; } public class Main{ public static void main(String[] args){ A a = new A(); B b = new B(); a.b=b; b.a=a; } }
在函數的結尾,a和b的計數均為2
先撤銷a,然后a的計數為1,在等待b.a對a的引用的撤銷,也就是在等待b的撤銷
對於b來講,也是同理
兩個對象都在等待對方撤銷,所有這兩個資源均不能釋放
- 標記-清除(Mark-Sweep)
此算法執行分兩階段。第一階段從引用根節點開始標記所有被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。此算法需要暫停整個應用,同時,會產生內存碎片。 - 復制(Copying)
此算法把內存空間划為兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象復制到另外一個區域中。次算法每次只處理正在使用中的對象,因此復制成本比較小,同時復制過去以后還能進行相應的內存整理,不過出現"碎片"問題。當然,此算法的缺點也是很明顯的,就是需要兩倍內存空間。 - 標記-整理(Mark-Compact)
此算法結合了"標記-清除"和"復制"兩個算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,把清除未標記對象並且把存活對象"壓縮"到堆的其中一塊,按順序排放。此算法避免了"標記-清除"的碎片問題,同時也避免了"復制"算法的空間問題。 - 增量收集(Incremental Collecting)
實施垃圾回收算法,即:在應用進行的同時進行垃圾回收。不知道什么原因JDK5.0中的收集器沒有使用這種算法的。 - 分代(Generational Collecting)
基於對對象生命周期分析后得出的垃圾回收算法。把對象分為年青代、年老代、持久代,對不同生命周期的對象使用不同的算法(上述方式中的一個)進行回收。現在的垃圾回收器(從J2SE1.2開始)都是使用此算法的。