1. 程式人生 > >Android gc與記憶體洩漏,溢位的理解

Android gc與記憶體洩漏,溢位的理解

GC介紹

在java中垃圾回收是自動釋放的,不像c/c++需要手動釋放,手動釋放可能處理不當,

會造成記憶體洩漏與資料混亂等等影響。

GC常用的回收演算法

1,計數

引用計數是垃圾收集器中的早期策略。在這種方法中,堆中每個物件(不是引用)都有一個引用計數。

當一個物件被建立時,且將該物件分配給一個變數,該變數計數設定為1。

當任何其它變數被賦值為這個物件的引用時,計數加1(a = b,則b引用的物件+1),

但當一個物件的某個引用超過了生命週期或者被設定為一個新值時,物件的引用計數減1。

任何引用計數為0的物件可以被當作垃圾收集。當一個物件被垃圾收集時,它引用的任何物件計數減1。

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


缺點: 無法檢測出迴圈引用。如父物件有一個對子物件的引用,子物件反過來引用父物件。

這樣,他們的引用計數永遠不可能為0.

2,標記跟蹤

現在大多數JVM採用物件引用遍歷。物件引用遍歷從一組物件開始,沿著整個物件圖上的每條連結,

遞迴確定可到達(reachable)的物件。如果某物件不能從這些根物件的一個(至少一個)到達,

則將它作為垃圾收集。在物件遍歷階段,GC必須記住哪些物件可以到達,以便刪除不可到達的物件,

這稱為標記(marking)物件。

下一步,GC要刪除不可到達的物件。刪除時,有些GC只是簡單的掃描堆疊,

刪除未標記的未標記的物件,並釋放它們的記憶體以生成新的物件,這叫做清除(sweeping)。

這種方法的問題在於記憶體會分成好多小段,而它們不足以用於新的物件,但是組合起來卻很大。

因此,許多GC可以重新組織記憶體中的物件,並進行壓縮(compact),形成可利用的空間。


為此,GC需要停止其他的活動活動。這種方法意味著所有與應用程式相關的工作停止,

只有GC執行。結果,在響應期間增減了許多混雜請求。

另外,更復雜的 GC不斷增加或同時執行以減少或者清除應用程式的中斷。

有的GC使用單執行緒完成這項工作,有的則採用多執行緒以增加效率。

3,在Java中還有很多收集器的演算法,copiny,標記壓縮,增量等等。

GC回收過程

垃圾回收執行緒會從“根集(Root Set)”開始進行物件引用的遍歷。


所謂的“根集”,就是正在執行的執行緒中,可以訪問的引用變數 的 集合(比如所有執行緒當前函式的引數和區域性變數、

當前類的成員變數等等)。


垃圾回收執行緒先找出被根集直接引用的所有物件(不妨叫集合1),


然後再找出被集合 1直接引用的所有物件(不妨叫集合2),


然後再找出被集合2直接引用的所有物件......如此迴圈往復,直到把能遍歷到的物件都遍歷完。


凡是從根集通過上述遍歷可以到達的物件,都稱為可達物件或有效物件;

反之,則是不可達物件或失效物件(也就是垃圾)。


凡是從根集通過上述遍歷可以到達的物件,都稱為可達物件或有效物件;

反之,則是不可達物件或失效物件(也就是垃圾)。

GC回收觸法原因

  • GC_CONCURRENT :當堆記憶體增長到一定程度時會觸發。此時觸發可以對堆中的沒有用的物件及時進行回收,騰出空間供新的物件申請,避免進行不必要的增大堆記憶體的操作。
  • GC_EXPLICIT :當程式中呼叫System.gc()方法觸發。這個方法應避免出現在程式中呼叫。因為JVM有足夠的能力來控制垃圾回收。
  • GC_EXTERNAL_MALLOC :當Bitmap和NIO Direct ByteBuffer物件分配外部儲存(機器記憶體,非Dalvik堆記憶體)觸發。這個日誌只有在2.3之前存在,從2.3系統開始,垃圾回收進行了調整,前面的物件都會儲存到Dalivik堆記憶體中。所以在2.3系統之後,你就再也不會看到這種資訊了。
  • GC_FOR_MALLOC  :當堆記憶體已滿,系統需要更多記憶體的時候觸發。這條日誌出現後意味著JVM要暫停你的程式進行垃圾回收操作。
  • GC_HPROF_DUMP_HEAP :當建立一個記憶體分析檔案HPROF時觸發。

總結:既然GC去對記憶體進行回收為什麼會有記憶體洩漏?

記憶體洩漏

記憶體洩漏也稱作“儲存滲漏”,用動態儲存分配函式動態開闢的空間,

在使用完畢後,GC並沒有進行對它回收(注意:GC是不會回收直接或間接地引用到gc roots的物件),

導致未釋放,結果導致一直佔據該記憶體單元。直到程式結束。

(其實說白了就是該記憶體空間使用完畢之後未回/收)即所謂記憶體洩漏。

補充Java記憶體洩漏指的是程序中某些物件(垃圾物件)已經沒有使用價值了,

但是它們卻可以直接或間接地引用到gc roots導致無法被GC回收。無用的物件佔據著記憶體空間,

使得實際可使用記憶體變小,形象地說法就是記憶體洩漏。

記憶體溢位

記憶體溢位(out of memory)通俗理解就是記憶體不夠,通常在執行大型軟體或遊戲時,

軟體或遊戲所需要的記憶體遠遠超出了你主機內安裝的記憶體所承受大小,就叫記憶體溢位。

此時軟體或遊戲就執行不了,系統會提示記憶體溢位,有時候會自動關閉軟體。

Android的虛擬機器是基於暫存器的Dalvik,它的最大堆大小一般是16M,有的機器為24M。

因此我們所能利用的記憶體空間是有限的。如果我們的記憶體佔用超過了一定的水平就會出現OutOfMemory的錯誤。

參照以下各位老兄的幸苦勞動: