JVM 垃圾回收机制和常见算法
理論上來講 Sun 公司只定義了垃圾回收機制規則而不局限于其實現算法,因此不同廠商生產的虛擬機采用的算法也不盡相同。
GC(Garbage Collector)在回收對象前首先必須發現那些無用的對象,如何去發現定位這些無用的對象?
常用的搜索算法如下:
引用計數器算法(廢棄)
引用計數器算法是給每個對象設置一個計數器,當有地方引用這個對象的時候,計數器+1,當引用失效的時候,計數器-1,當計數器為 0 的時候,JVM 就認為對象不再被使用,是“垃圾”了。
引用計數器實現簡單,效率高;但是不能解決循環引用問問題(A 對象引用 B 對象,B 對象又引用 A 對象,但是A,B 對象已不被任何其他對象引用),同時每次計數器的增加和減少都帶來了很多額外的開銷,所以在 JDK1.1 之后,這個算法已經不再使用了。
根搜索算法(使用)
根搜索算法是通過一些“GC Roots”對象作為起點,從這些節點開始往下搜索,搜索通過的路徑成為引用鏈(Reference Chain),當一個對象沒有被 GC Roots 的引用鏈連接的時候,說明這個對象是不可用的。
GC Roots 對象包括:
a) 虛擬機棧(棧幀中的本地變量表)中的引用的對象。
b) 方法區域中的類靜態屬性引用的對象。
c) 方法區域中常量引用的對象。
d) 本地方法棧中 JNI(Native 方法)的引用的對象。
通過上面的算法搜索到無用對象之后,就是回收過程,回收算法如下:
標記—清除算法(Mark-Sweep)(DVM 使用的算法)
標記—清除算法包括兩個階段:“標記”和“清除”。在標記階段,確定所有要回收的對象,并做標記。清除階段緊隨標記階段,將標記階段確定不可用的對象清除。標記—清除算法是基礎的收集算法,標記和清除階段的效率不高,而且清除后回產生大量的不連續空間,這樣當程序需要分配大內存對象時,可能無法找到足夠的連續空間。
復制算法(Copying)
復制算法是把內存分成大小相等的兩塊,每次使用其中一塊,當垃圾回收的時候,把存活的對象復制到另一塊上,然后把這塊內存整個清理掉。復制算法實現簡單,運行效率高,但是由于每次只能使用其中的一半,造成內存的利用率不高。現在的 JVM 用復制方法收集新生代,由于新生代中大部分對象(98%)都是朝生夕死的,所以兩塊內存的比例不是 1:1(大概是 8:1)。
標記—整理算法(Mark-Compact)
標記—整理算法和標記—清除算法一樣,但是標記—整理算法不是把存活對象復制到另一塊內存,而是把存活對象往內存的一端移動,然后直接回收邊界以外的內存。標記—整理算法提高了內存的利用率,并且它適合在收集對象存活時間較長的老年代。
分代收集(Generational Collection)
分代收集是根據對象的存活時間把內存分為新生代和老年代,根據各個代對象的存活特點,每個代采用不同的垃圾回收算法。新生代采用復制算法,老年代采用標記—整理算法。垃圾算法的實現涉及大量的程序細節,而且不同的虛擬機平臺實現的方法也各不相同。
總結
以上是生活随笔為你收集整理的JVM 垃圾回收机制和常见算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 堆(heap)和栈(stack)的区别
- 下一篇: JVM 的内存结构和内存分配