Android記憶體回收機制

來源:互聯網
上載者:User

標籤:

 1.垃圾收集演算法的核心思想

  Java語言建立了垃圾收集機制,用以跟蹤正在使用的對象和發現並回收不再使用(引用)的對象。該機制可以有效防範動態記憶體分配中可能發生的兩個危險:因記憶體垃圾過多而引發的記憶體耗盡,以及不恰當的記憶體釋放所造成的記憶體非法引用。

  垃圾收集演算法的核心思想是:對虛擬機器可用記憶體空間,即堆空間中的對象進行識別,如果對象正在被引用,那麼稱其為存活對象,反之,如果對象不再被引用,則為垃圾對象,可以回收其佔據的空間,用於再分配。垃圾收集演算法的選擇和垃圾收集系統參數的合理調節直接影響著系統效能,因此需要開發人員做比較深入的瞭解。

2.觸發主GC(Garbage Collector)的條件

  JVM進行次GC的頻率很高,但因為這種GC佔用時間極短,所以對系統產生的影響不大。更值得關注的是主GC的觸發條件,因為它對系統影響很明顯。總的來說,有兩個條件會觸發主GC:

  ①當應用程式空閑時,即沒有應用線程在運行時,GC會被調用。因為GC在優先順序最低的線程中進行,所以當應用忙時,GC線程就不會被調用,但以下條件除外。

  ②Java堆記憶體不足時,GC會被調用。當應用線程在運行,並在運行過程中建立新對象,若這時記憶體空間不足,JVM就會強制地調用GC線程,以便回收記憶體用於新的分配。若GC一次之後仍不能滿足記憶體配置的要求,JVM會再進行兩次GC作進一步的嘗試,若仍無法滿足要求,則 JVM將報“out of memory”的錯誤,Java應用將停止。

  由於是否進行主GC由JVM根據系統內容決定,而系統內容在不斷的變化當中,所以主GC的運行具有不確定性,無法預計它何時必然出現,但可以確定的是對一個長期啟動並執行應用來說,其主GC是反覆進行的。

3.減少GC開銷的措施

  根據上述GC的機制,程式的運行會直接影響系統內容的變化,從而影響GC的觸發。若不針對GC的特點進行設計和編碼,就會出現記憶體駐留等一系列負面影響。為了避免這些影響,基本的原則就是儘可能地減少垃圾和減少GC過程中的開銷。具體措施包括以下幾個方面:

  (1)不要顯式調用System.gc()

  此函數建議JVM進行主GC,雖然只是建議而非一定,但很多情況下它會觸發主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數。

  (2)盡量減少臨時對象的使用

  臨時對象在跳出函數調用後,會成為垃圾,少用臨時變數就相當於減少了垃圾的產生,從而延長了出現上述第二個觸發條件出現的時間,減少了主GC的機會。

  (3)對象不用時最好顯式置為Null

  一般而言,為Null的對象都會被作為垃圾處理,所以將不用的對象顯式地設為Null,有利於GC收集器判定垃圾,從而提高了GC的效率。

  (4)盡量使用StringBuffer,而不用String來累加字串(詳見blog另一篇文章JAVA中String與StringBuffer)

  由於String是固定長的字串對象,累加String對象時,並非在一個String對象中擴增,而是重新建立新的String對象,如 Str5=Str1+Str2+Str3+Str4,這條語句執行過程中會產生多個垃圾對象,因為對次作“+”操作時都必須建立新的String對象,但這些過渡對象對系統來說是沒有實際意義的,只會增加更多的垃圾。避免這種情況可以改用StringBuffer來累加字串,因StringBuffer 是可變長的,它在原有基礎上進行擴增,不會產生中間對象。

  (5)能用基本類型如Int,Long,就不用Integer,Long對象

  基本類型變數佔用的記憶體資源比相應對象佔用的少得多,如果沒有必要,最好使用基本變數。

  (6)盡量少用靜態物件變數

  靜態變數屬於全域變數,不會被GC回收,它們會一直佔用記憶體。

  (7)分散對象建立或刪除的時間

  集中在短時間內大量建立新對象,特別是大對象,會導致突然需要大量記憶體,JVM在面臨這種情況時,只能進行主GC,以回收記憶體或整合記憶體片段,從而增加主GC的頻率。集中刪除對象,道理也是一樣的。它使得突然出現了大量的垃圾對象,空閑空間必然減少,從而大大增加了下一次建立新對象時強制主GC 的機會。

4、如果確定某個對象是“垃圾”?

既然垃圾收集器的任務是回收垃圾對象所佔的空間供新的對象使用,那麼垃圾收集器如何確定某個對象是“垃圾”?—即通過什麼方法判斷一個對象可以被回收了。

4.1 引用計數演算法

  在java中是通過引用來和對象進行關聯的,也就是說如果要操作對象,必須通過引用來進行。那麼很顯然一個簡單的辦法就是通過引用計數來判斷一個對象是否可以被回收。不失一般性,如果一個對象沒有任何引用與之關聯,則說明該對象基本不太可能在其他地方被使用到,那麼這個對象就成為可被回收的對象了。這種方式成為引用計數法

  這種方式的特點是實現簡單,而且效率較高,但是它無法解決循環參考的問題,因此在Java中並沒有採用這種方式(Python採用的是引用計數法)。

 1 public class Main { 2     public static void main(String[] args) { 3         MyObject object1 = new MyObject(); 4         MyObject object2 = new MyObject(); 5           6         object1.object = object2; 7         object2.object = object1; 8           9         object1 = null;10         object2 = null;11     }12 }13  14 class MyObject{15     public Object object = null;16 }

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

  為瞭解決這個問題,在Java中採取了 可達性分析法。該方法的基本思想是通過一系列的“GC Roots”對象作為起點進行搜尋,如果在“GC Roots”和一個對象之間沒有可達路徑,則稱該對象是不可達的,不過要注意的是被判定為不可達的對象不一定就會成為可回收對象。被判定為不可達的對象要成為可回收對象必須至少經曆兩次標記過程,如果在這兩次標記過程中仍然沒有逃脫成為可回收對象的可能性,則基本上就真的成為可回收對象了。

4.2 可達性分析演算法

  在主流的商用程式語言(Java、C#,甚至包括前面提到的古老的Lisp)的主流實現中,都是稱通過可達性分析(Reachability Analysis)來判定對象是否存活的。這個演算法的基本思路就是通過一系列的稱為“GC Roots”的對象作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連(用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是停用。虛擬機器中的對象如果對於gc roots節點不可達的,那麼就會被回收掉。

4.3 範例

  下面來看個例子:

1 Object aobj = new Object ( ) ;2 Object bobj = new Object ( ) ;3 Object cobj = new Object ( ) ;4 aobj = bobj;5 aobj = cobj;6 cobj = null;7 aobj = null;

  第幾行有可能會使得某個對象成為可回收對象?第7行的代碼會導致有對象會成為可回收對象。

  再看一個例子:

1 String str = new String("hello");2 SoftReference<String> sr = new SoftReference<String>(new String("java"));3 WeakReference<String> wr = new WeakReference<String>(new String("world"));

  這三句哪句會使得String對象成為可回收對象?第2句和第3句,第2句在記憶體不足的情況下會將String對象判定為可回收對象,第3句無論什麼情況下String對象都會被判定為可回收對象。

小結——最後總結一下平常遇到的比較常見的將對象判定為可回收對象的情況:

  1)引用置空:顯示地將某個引用賦值為null或者將已經指向某個對象的引用指向新的對象,比如下面的代碼:

1 Object obj = new Object();2 obj = null;3 Object obj1 = new Object();4 Object obj2 = new Object();5 obj1 = obj2;

  2)局部引用:局部引用所指向的對象,比如下面這段代碼:

1 void fun() {2  3 .....4     for(int i=0;i<10;i++) {5         Object obj = new Object();6         System.out.println(obj.getClass());7     }   8 }

  迴圈每執行完一次,產生的Object對象都會成為可回收的對象。

  3)弱引用:只有弱引用與其關聯的對象,比如:

 1 WeakReference<String> wr = new WeakReference<String>(new String("world")); 

5、典型的記憶體回收演算法5.1 Mark-Sweep(標記-清除)演算法

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

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

5.2 Copying(複製)演算法

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

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

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

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

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

  

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

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

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

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

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

http://blog.csdn.net/wuqiong_524itcast/article/details/25378685

http://www.cnblogs.com/dolphin0520/p/3783345.html

Android記憶體回收機制

聯繫我們

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