java 記憶體回收,記憶體回收

來源:互聯網
上載者:User

java 記憶體回收,記憶體回收

java 回收機制 garbage collection gc 這個是JVM來處理的

回收分2個步驟:
1. 如果確認某個對象是“垃圾”?

1) 引用計數法 如果一個對象被建立但是沒有任何地方被使用到,那麼這個對象就成為可被回收的對象。 Test test=new Test();

這種方法 簡單,效率高,但是無法解決循環參考的問題,所以java沒有採用這種方法,python採用的是引用計數法

2)什麼是循環參考?
MyObject object1 = new MyObject();
MyObject object2 = new MyObject();
// 兩個對象相互引用
object1.object = object2;
object2.object = object1;

//兩個對象都設定為null object1和object2指向的對象已經不可能再被訪問 由於它們互相引用對方,導致它們的引用計數都不為0,那麼垃圾收集器就永遠不會回收它們。
object1 = null;
object2 = null;

3) 所以java採用的是可達性分析法:通過"GC Roots"對象作為起點搜尋,如果在"GC Roots"和一個對象之間沒有可達路徑,那麼該對象是不可達的,這個時候不會立即回收,而是最少要被標記兩次
那麼對象才會由不可達對象變為可回收對象。

java 平時如何將常見的對象判定為可回收對象:

1) 顯示地將某個引用賦值為null或者將已經指向某個對象的引用指向新的對象

Object obj = new Object();
//賦值為null
obj = null;

Object obj1 = new Object();
Object obj2 = new Object();
//指向新的對象 那麼原來的對象就沒有了 因為指向新對象了
obj1 = obj2;


2) 局部引用的對象:
for(int i=0;i<10;i++) {
Object obj = new Object();
System.out.println(obj.getClass());
}
object對象每迴圈執行完一次,都會成為可回收的對象


3)弱引用與其關聯的對象,
WeakReference<String> wr = new WeakReference<String>(new String("world"));

 

2 如何回收


1) 典型的垃圾收集演算法

確認了垃圾後,開始回收,那麼如何高效的進行記憶體回收呢? 下面幾個辦法

1. Mark-Sweep(標記-清除)演算法

標記-清除演算法分為兩個階段:標記階段和清除階段。
標記階段:標記出所以需要被回收的對象, 可達性分析法
清除階段:回收被標記的對象所佔用的空間

這種方法容易產生記憶體片段,片段太多可能會導致後續過程中為大對象分配空間時記憶體不夠而提前出發新的一次垃圾收集動作

2. Copying(複製)演算法

將記憶體容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的對象複製到另外一塊上面,然後再把已使用的記憶體空間一次清理掉,這樣一來就不容易出現記憶體片段的問題。

但是這種方法會將記憶體控制項減半,

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

演算法標記階段和Mark-Sweep一樣,但是在完成標記之後,它不是直接清理可回收對象,而是將存活對象都向一端移動,然後清理掉端邊界以外的記憶體

4 Generational Collection(分代收集)演算法

分代收集演算法是目前大部分JVM的垃圾收集器採用的演算法

根據對象存活的生命週期將記憶體分為若干個不同地區,一般是老年代和新生代

老年代: 每次垃圾收集只有少量對象需要回收 一般使用Mark-Compact

新生代: 每次記憶體回收時都有大量的對象需要被回收,那麼可以根據不同代的特點採取最合適的收集演算法
使用copying演算法,因為新生代中每次記憶體回收都要回收大部分,但是不是按照1:1的比例來劃分新生代的空間的,一般是新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor控制項,每次
使用Eden空間和一塊Survivor空間,回收時,將Eden和Survivor中還存活的對象複製到另一塊Survivor空間中,然後清理掉Eden和剛才使用過的Survivor空間。


2) 典型的垃圾收集器

1. Serial/Serial Old:它是一個單線程收集器,並且在它進行垃圾收集時,必須暫停所有使用者線程
Serial收集器是針對新生代的收集器,採用的是Copying演算法,Serial Old收集器是針對老年代的收集器,採用的是Mark-Compact演算法。它的優點是實現簡單高效,但是缺點是會給使用者帶來停頓。

2. ParNew是Serial收集器的多線程版本,使用多個線程進行垃圾收集

3. Parallel Scavenge收集器是一個新生代的多線程收集器(並行收集器)
它在回收期間不需要暫停其他使用者線程,其採用的是Copying演算法,該收集器與前兩個收集器有所不同,它主要是為了達到一個可控的輸送量。

4. Parallel Old是Parallel Scavenge收集器的老年代版本(並行收集器),使用多線程和Mark-Compact演算法。 因為是老年代麼

5. CMS(Current Mark Sweep)收集器是一種以擷取最短回收停頓時間為目標的收集器,它是一種並發收集器,採用的是Mark-Sweep演算法。

6. G1收集器是當今收集器技術發展最前沿的成果,它是一款面向服務端應用的收集器,它能充分利用多CPU、多核環境。因此它是一款並行與並發收集器,並且它能建立可預測的停頓時間模型。

記憶體配置:
一個對象的記憶體主要分配到新生代的Eden和From Space,少數情況下才會到老生代,如果新生代的Eden Space和From Space的空間不足,則會發起一次GC

GC的過程中,1.會將Eden Space和From Space中的存活對象移動到To Space, From和To就是兩塊Survivor
2.然後將Eden Space和From Space進行清理
3.如果To Space控制項無法儲存某個對象,就會將該對象移動到老年代中

gc後,使用的便是Eden space和To Space了(因為將From Space清理了 將存活的對象放到了To Space了)

下次GC時會將存活對象複製到From Space,如此反覆迴圈。當對象在Survivor區躲過一次GC的話,其對象年齡便會加1,預設情況下,如果對象年齡達到15歲,就會移動到老年代中。


一般來說,大對象會被直接分配到老年代,所謂的大對象是指需要大量連續儲存空間的對象,最常見的一種大對象就是大數組


byte[] data = new byte[4*1024*1024]

這種一般會直接在老年代分配儲存空間。

當然分配的規則並不是百分之百固定的,這要取決於當前使用的是哪種垃圾收集器組合和JVM的相關參數。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.