1. 程式人生 > >JAVA GC垃圾回收機制簡單易懂的理解

JAVA GC垃圾回收機制簡單易懂的理解

一、什麼是垃圾回收機制?

JAVA語言的一個顯著特點是垃圾回收機制,相比C++而言,程式設計師不需要關心繁瑣的記憶體管理問題。

所以,簡單的說,垃圾回收機制就是JVM利用一些列演算法對記憶體進行管理,包括記憶體的分配與回收。

 

二、垃圾回收機制的原理是什麼呢?

其實垃圾回收機制的原理就是利用一些演算法進行記憶體的管理,從而有效的防止記憶體洩漏、有效的利用空閒空間(記憶體空間)。

三、垃圾回收機制所涉及的演算法?

1、計數法(Reference Counting Collector)

*注:以下count是我假設的一個引用計數變數名。

計數法是最早期的策略,堆中每個物件例項都有一個引用計數(count),當一個物件被建立且被一個變數引用時,count++;   

Object obj = new Object();   //此時該物件的計數器count則+1

當該物件的引用(obj)被其他變數引用時,計引計數(count)也會+1;

Object obj = new Object();   //此時該物件的計數器count則+1, count = 1
Object obj1 = obj;           //此時物件計數器count+1, count = 2

當一個物件例項的引用超過生命週期,或者被設定為一個新值得時候,count -1;

function void test(){
    Object obj = new Object();   //此時該物件的計數器count則+1, count = 1    
    Object obj1 = obj;           //此時物件計數器count+1, count = 2
    
    //情況一 :此時obj1被賦值新物件,則上面的count-1; count = 1;
    obj1 = new Object();         //當然,此處建立了新物件並被引用,也會有一個count_1 = 1;

    //情況二:當方法執行結束時,物件的引用超過了生命週期,則count也會-1; count=0
    //count = 0, 則會被視為垃圾被回收。
    return;
}

2.tracing演算法

從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點以後,繼續尋找這個節點的引用節點,當所有的引用節點尋找完畢之後,剩餘的節點則被認為是沒有被引用到的節點,即無用的節點。

 

3、標記-清除演算法。

標記-清除演算法採用從根集合進行掃描,對存活的物件物件標記,標記完畢後,再掃描整個空間中未被標記的物件,進行回收,如上圖所示。標記-清除演算法不需要進行物件的移動,並且僅對不存活的物件進行處理,在存活物件比較多的情況下極為高效,但由於標記-清除演算法直接回收不存活的物件,因此會造成記憶體碎片。

4、標記-整理演算法

標記-整理演算法採用標記-清除演算法一樣的方式進行物件的標記,但在清除時不同,在回收不存活的物件佔用的空間後,會將所有的存活物件往左端空閒空間移動,並更新對應的指標。標記-整理演算法是在標記-清除演算法的基礎上,又進行了物件的移動,因此成本更高,但是卻解決了記憶體碎片的問題

 

5、copying演算法(Compacting Collector)

該演算法的提出是為了克服控制代碼的開銷和解決堆碎片的垃圾回收。

 

5.generation演算法(Generational Collector)

分代的垃圾回收策略,是基於這樣一個事實:不同的物件的生命週期是不一樣的。因此,不同生命週期的物件可以採取不同的回收演算法,以便提高回收效率。

年輕代(Young Generation)

1.所有新生成的物件首先都是放在年輕代的。年輕代的目標就是儘可能快速的收集掉那些生命週期短的物件。

2.新生代記憶體按照8:1:1的比例分為一個eden區和兩個survivor(survivor0,survivor1)區。一個Eden區,兩個 Survivor區(一般而言)。大部分物件在Eden區中生成。回收時先將eden區存活物件複製到一個survivor0區,然後清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活物件複製到另一個survivor1區,然後清空eden和這個survivor0區,此時survivor0區是空的,然後將survivor0區和survivor1區交換,即保持survivor1區為空, 如此往復。

3.當survivor1區不足以存放 eden和survivor0的存活物件時,就將存活物件直接存放到老年代。若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都進行回收

4.新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)

年老代(Old Generation)

1.在年輕代中經歷了N次垃圾回收後仍然存活的物件,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命週期較長的物件。

2.記憶體比新生代也大很多(大概比例是1:2),當老年代記憶體滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代物件存活時間比較長,存活率標記高。

持久代(Permanent Generation)

用於存放靜態檔案,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者呼叫一些class,例如Hibernate 等,在這種時候需要設定一個比較大的持久代空間來存放這些執行過程中新增的類。

 

 

參考:https://www.cnblogs.com/andy-zcx/p/5522836.html