Android 之 記憶體管理
概述
在android的開發中,要時刻主要記憶體的分配和垃圾回收,因為系統為每一個dalvik虛擬機器分配的記憶體是有限的,在google的G1中,分配的最大堆大小隻有16M,後來的機器一般都為24M,實在是少的可憐。這樣就需要我們在開發過程中要時刻注意。不要因為自己的程式碼問題而造成OOM錯誤。
JAVA的記憶體管理
大家都知道,android應用層是由java開發的,android的davlik虛擬機器與jvm也類似,只不過它是基於暫存器的。因此要了解android的記憶體管理就必須得了解java的記憶體分配和垃圾回收機制。
在java中,是通過new關鍵字來為物件分配記憶體的,而記憶體的釋放是由垃圾收集器(GC)來回收的,工程師在開發的過程中,不需要顯式的去管理記憶體。但是這樣有可能在不知不覺中就會浪費了很多記憶體,最終導致java虛擬機器花費很多時間去進行垃圾回收,更嚴重的是造成JVM的OOM。因此,java工程師還是有必要了解JAVA的記憶體分配和垃圾回收機制。
- 記憶體結構
上面這張圖是JVM的結構圖,它主要四個部分組成:Class Loader子系統和執行引擎,執行時方法區和本地方法區,我們主要來看下RUNTIME DATA AREA區,也就是我們常說的JVM記憶體。從圖中可以看出,RUNTIMEDATA AREA區主要由5個部分組成:
- Method Area:被裝載的class的元資訊儲存在Method Area中,它是執行緒共享的
- Heap(堆):一個java虛擬機器例項中只存在一個堆空間,存放一些物件資訊,它是執行緒共享的
- Java棧: java虛擬機器直接對java棧進行兩種操作,以幀為單位的壓棧和出棧(非執行緒共享)
- 程式計數器(非執行緒共享)
- 本地方法棧(非執行緒共享)
- JVM的垃圾回收(GC)
JVM的垃圾原理是這樣的,它把物件分為年輕代(Young)、年老代(Tenured)、持久代(Perm),對不同生命週期的物件使用不同的垃圾回收演算法。
- 年輕代(Young)
年輕代分為三個區,一個eden區,兩個Survivor區。程式中生成的大部分新的物件都在Eden區中,當Eden區滿時,還存活的物件將被複制到其中一個Survivor區,當此Survivor區的物件佔用空間滿了時,此區存活的物件又被複制到另外一個Survivor區,當這個Survivor區也滿了的時候,從第一個Survivor區複製過來的並且此時還存活的物件,將被複制到年老代。
- 年老代(Tenured)
年老代存放的是上面年輕代複製過來的物件,也就是在年輕代中還存活的物件,並且區滿了複製過來的。一般來說,年老代中的物件生命週期都比較長。
- 持久代(Perm)
用於存放靜態的類和方法,持久代對垃圾回收沒有顯著的影響。
Android中記憶體洩露監測
在瞭解了JVM的記憶體管理後,我們再回過頭來看看,在android中應該怎樣來監測記憶體,從而看在應用中是否存在記憶體分配和垃圾回收問題而造成記憶體洩露情況。
在android中,有一個相對來說還不錯的工具,可以用來監測記憶體是否存在洩露情況:DDMS—Heap
使用方法比較簡單:
- 選擇DDMS檢視,並開啟Devices檢視和Heap檢視
- 點選選擇要監控的程式,比如:上圖中我選擇的是system_process
- 選中Devices檢視介面上的"update heap" 圖示
- 點選Heap檢視中的"Cause GC" 按鈕(相當於向虛擬機器傳送了一次GC請求的操作)
在Heap檢視中選擇想要監控的Type,一般我們會觀察dataobject的 total size的變化,正常情況下total size的值會穩定在一個有限的範圍內,也就說程式中的程式碼良好,沒有造成程式中的物件不被回收的情況。如果程式碼中存在沒有釋放物件引用的情況,那麼data object的total size在每次GC之後都不會有明顯的回落,隨著操作次數的增加而total size也在不斷的增加。(說明:選擇好data object後,不斷的操作應用,這樣才可以看出total size的變化)。如果totalsize確實是在不斷增加而沒有回落,說明程式中有沒有被釋放的資源引用。那麼我們應該怎麼來定位呢?
Android中記憶體洩露定位
Mat(memory analyzer tools)是我們常用的用來定位記憶體洩露的工具,如果你使用ADT,並且安裝了MAT的eclipse外掛,你需要做的是進入DDMS檢視的Devices檢視:
點選"dump HPROF file"按鈕,然後使用MAT分析下載下來的檔案。
下面列出了存在的問題,點選detail進去,會列出詳細的,可能會存在問題的程式碼:
關於MAT的使用可以參考:http://www.blogjava.net/rosen/archive/2010/06/13/323522.html
這位兄弟寫的比較詳細。
總結
不管是java還是android,都應該瞭解記憶體分配和垃圾回收機制,工程師要做到寫的程式碼中沒有bad code很難,關鍵是在出現問題的時候該怎麼去排查。
相關文章
- Android記憶體管理Android記憶體
- 記憶體管理兩部曲之實體記憶體管理記憶體
- 記憶體管理兩部曲之虛擬記憶體管理記憶體
- Android 是如何管理 App 記憶體的 — Android 記憶體優化第二彈AndroidAPP記憶體優化
- 記憶體管理 記憶體管理概述記憶體
- 溫故之.NET記憶體管理記憶體
- Android效能優化篇之記憶體優化--記憶體洩漏Android優化記憶體
- 記憶體管理篇——實體記憶體的管理記憶體
- android記憶體管理機制與優化Android記憶體優化
- JVM讀書筆記之記憶體管理JVM筆記記憶體
- 【記憶體管理】記憶體佈局記憶體
- Java的記憶體管理機制之記憶體區域劃分Java記憶體
- Android 效能優化之記憶體優化Android優化記憶體
- Android Handler機制之記憶體洩漏Android記憶體
- Python分享之Python的記憶體管理Python記憶體
- Swift 記憶體管理之 weak 與 unownedSwift記憶體
- 通俗易懂,android是如何管理記憶體的Android記憶體
- Java的記憶體 -JVM 記憶體管理Java記憶體JVM
- Go:記憶體管理與記憶體清理Go記憶體
- AntDB記憶體管理之記憶體上下文之記憶體上下文機制是怎麼實現的記憶體
- Android記憶體優化之圖片優化Android記憶體優化
- Android效能最佳化之記憶體洩露Android記憶體洩露
- Paddle原始碼之記憶體管理技術原始碼記憶體
- 【記憶體管理】Oracle AMM自動記憶體管理詳解記憶體Oracle
- Android記憶體洩漏Android記憶體
- Android 記憶體抖動Android記憶體
- Android 記憶體洩漏Android記憶體
- Android記憶體優化Android記憶體優化
- JavaScript 記憶體管理JavaScript記憶體
- iOS 記憶體管理iOS記憶體
- OC記憶體管理記憶體
- 記憶體管理-swMemoryGlobal記憶體
- Flink記憶體管理記憶體
- MySQL記憶體管理MySql記憶體
- 【記憶體管理】Oracle如何使用ASMM自動共享記憶體管理記憶體OracleASM
- linux記憶體管理(一)實體記憶體的組織和記憶體分配Linux記憶體
- Android彈藥庫——記憶體管理機制與程式模型Android記憶體模型
- Linux實體記憶體管理Linux記憶體
- Android Note - 記憶體優化Android記憶體優化