java----java記憶體回收演算法

來源:互聯網
上載者:User

標籤:ane   導致   close   --   例子   核心   循環參考   代碼   compact   

1.引用計數法(Reference Counting Collector)

1.1演算法分析

引用計數是垃圾收集器中的早期策略。在這種方法中,堆中每個對象執行個體都有一個引用計數。當一個對象被建立時,且將該對象執行個體分配給一個變數,該變數計數設定為1。當任何其它變數被賦值為這個對象的引用時,計數加1(a = b,則b引用的對象執行個體的計數器+1),但當一個對象執行個體的某個引用超過了生命週期或者被設定為一個新值時,對象執行個體的引用計數器減1。任何引用計數器為0的對象執行個體可以被當作垃圾收集。當一個對象執行個體被垃圾收集時,它引用的任何對象執行個體的引用計數器減1。

1.2優缺點

優點:

引用計數收集器可以很快的執行,交織在程式運行中。對程式需要不被長時間打斷的即時環境比較有利。

缺點:

無法檢測出循環參考。如父物件有一個對子物件的引用,子物件反過來引用父物件。這樣,他們的引用計數永遠不可能為0.

1.3引用計數演算法無法解決循環參考問題,例如:

public class Main {    public static void main(String[] args) {        MyObject object1 = new MyObject();        MyObject object2 = new MyObject();                  object1.object = object2;        object2.object = object1;                  object1 = null;        object2 = null;    }}

 

最後面兩句將object1和object2賦值為null,也就是說object1和object2指向的對象已經不可能再被訪問,但是由於它們互相引用對方,導致它們的引用計數器都不為0,那麼垃圾收集器就永遠不會回收它們。

2.Mark-Sweep(標記-清除)Tracing Collector(tracing演算法)

  這是最基礎的記憶體回收演算法,之所以說它是最基礎的是因為它最容易實現,思想也是最簡單的。標記-清除演算法分為兩個階段:標記階段和清除階段。標記階段的任務是標記出所有需要被回收的對象,清除階段就是回收被標記的對象所佔用的空間。具體過程如所示:

  可以很容易看出標記-清除演算法實現起來比較容易,但是有一個比較嚴重的問題就是容易產生記憶體片段,片段太多可能會導致後續過程中需要為大對象分配空間時無法找到足夠的空間而提前觸發新的一次垃圾收集動作。

3.Copying(複製)演算法

  為瞭解決Mark-Sweep演算法的缺陷,Copying演算法就被提了出來。它將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的對象複製到另外一塊上面,然後再把已使用的記憶體空間一次清理掉,這樣一來就不容易出現記憶體片段的問題。具體過程如所示:

  這種演算法雖然實現簡單,運行高效且不容易產生記憶體片段,但是卻對記憶體空間的使用做出了高昂的代價,因為能夠使用的記憶體縮減到原來的一半。

  很顯然,Copying演算法的效率跟存活對象的數目多少有很大的關係,如果存活對象很多,那麼Copying演算法的效率將會大大降低。

4.Mark-Compact(標記-整理)演算法

  為瞭解決Copying演算法的缺陷,充分利用記憶體空間,提出了Mark-Compact演算法。該演算法標記階段和Mark-Sweep一樣,但是在完成標記之後,它不是直接清理可回收對象,而是將存活對象都向一端移動,然後清理掉端邊界以外的記憶體。具體過程如所示:

  

5.Generational Collection(分代收集)演算法

  分代收集演算法是目前大部分JVM的垃圾收集器採用的演算法。它的核心思想是根據對象存活的生命週期將記憶體劃分為若干個不同的地區。一般情況下將堆區劃分為老年代(Tenured Generation)和新生代(Young Generation),老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次記憶體回收時都有大量的對象需要被回收,那麼就可以根據不同代的特點採取最適合的收集演算法。

  目前大部分垃圾收集器對於新生代都採取Copying演算法,因為新生代中每次記憶體回收都要回收大部分對象,也就是說需要複製的操作次數較少,但是實際中並不是按照1:1的比例來劃分新生代的空間的,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象複製到另一塊Survivor空間中,然後清理掉Eden和剛才使用過的Survivor空間。

  而由於老年代的特點是每次回收都只回收少量對象,一般使用的是Mark-Compact演算法。

  注意,在堆區之外還有一個代就是永久代(Permanet Generation),它用來儲存class類、常量、方法描述等。對永久代的回收主要回收兩部分內容:廢棄常量和無用的類。

 

 

垃圾收集器

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

 

Serial收集器(複製演算法)

新生代單線程收集器,標記和清理都是單線程,優點是簡單高效。

Serial Old收集器(標記-整理演算法)

老年代單線程收集器,Serial收集器的老年代版本。

ParNew收集器(停止-複製演算法) 

新生代收集器,可以認為是Serial收集器的多線程版本,在多核CPU環境下有著比Serial更好的表現。

Parallel Scavenge收集器(停止-複製演算法)

並行收集器,追求高輸送量,高效利用CPU。輸送量一般為99%, 輸送量= 使用者線程時間/(使用者線程時間+GC線程時間)。適合後台應用等對互動相應要求不高的情境。

Parallel Old收集器(停止-複製演算法)

Parallel Scavenge收集器的老年代版本,並行收集器,輸送量優先

CMS(Concurrent Mark Sweep)收集器(標記-清理演算法)

高並發、低停頓,追求最短GC回收停頓時間,cpu佔用比較高,回應時間快,停頓時間短,多核cpu 追求高回應時間的選擇

 

 

GC的執行機制

由於對象進行了分代處理,因此記憶體回收地區、時間也不一樣。GC有兩種類型:Scavenge GC和Full GC。

Scavenge GC

一般情況下,當新對象產生,並且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden地區進行GC,清除非存活對象,並且把尚且存活的對象移動到Survivor區。然後整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這裡需要使用速度快、效率高的演算法,使Eden去能儘快空閑出來。

Full GC

對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個堆進行回收,所以比Scavenge GC要慢,因此應該儘可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對於FullGC的調節。有如下原因可能導致Full GC:

1.年老代(Tenured)被寫滿

2.持久代(Perm)被寫滿

3.System.gc()被顯示調用

4.上一次GC之後Heap的各域分配策略動態變化

 

Java有了GC同樣會出現記憶體泄露問題

靜態集合類像HashMap、Vector等的使用最容易出現記憶體泄露,這些靜態變數的生命週期和應用程式一致,所有的對象Object也不能被釋放,因為他們也將一直被Vector等應用著。

Static Vector v = new Vector(); for (int i = 1; i<100; i++) {     Object o = new Object();     v.add(o);     o = null; }

在這個例子中,代碼棧中存在Vector 對象的引用 v 和 Object 對象的引用 o 。在 For 迴圈中,我們不斷的產生新的對象,然後將其添加到 Vector 對象中,之後將 o 引用置空。問題是當 o 引用被置空後,如果發生 GC,我們建立的 Object 對象是否能夠被 GC 回收呢?答案是否定的。因為, GC 在跟蹤代碼棧中的引用時,會發現 v 引用,而繼續往下跟蹤,就會發現 v 引用指向的記憶體空間中又存在指向 Object 對象的引用。也就是說儘管o 引用已經被置空,但是 Object 對象仍然存在其他的引用,是可以被訪問到的,所以 GC 無法將其釋放掉。如果在此迴圈之後, Object 對象對程式已經沒有任何作用,那麼我們就認為此 Java 程式發生了記憶體流失。

2.各種串連,資料庫連接,網路連接,IO串連等沒有顯示調用close關閉,不被GC回收導致記憶體泄露。

3.監聽器的使用,在釋放對象的同時沒有相應刪除監聽器的時候也可能導致記憶體泄露。

java----java記憶體回收演算法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.