Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之內存管理-內存監測-內存優化

Android之內存管理-內存監測-內存優化

編輯:關於Android編程

1.1 Dalvik
Dalvik虛擬機是Android程序的虛擬機,是Android中Java程序的運行基礎。其指令集基於寄存器架構,執行其特有的文件格式——dex字節碼來完成對象生命周期管理、堆棧管理、線程管理、安全異常管理、垃圾回收等重要功能。
Dalvik虛擬機的內存大體上可以分為 Java Object Heap、Bitmap Memory和Native Heap三種。
Java Object Heap:用於分配對象
Bitmap Memory:用來處理圖像,≥Android 3.0, 歸到Object Heap中
Native Heap: malloc分配,受系統限制

1.2 查看單個進程最大內存限制

Android設備出廠以後,java虛擬機對單個應用的最大內存分配就確定下來了,超出這個值就會OOM。

這個屬性值是定義在/system/build.prop文件中的
dalvik.vm.heapstartsize=8m //它表示堆分配的初始大小

它會影響到整個系統對RAM的使用程度,和第一次使用應用時的流暢程度。它值越小,系統ram消耗越慢,但一些較大應用一開始不夠用,需要調用gc和堆調整策略,導致應用反應較慢。它值越大,這個值越大系統ram消耗越快,但是應用更流暢。

dalvik.vm.heapgrowthlimit=64m // 單個應用可用最大內存
主要對應的是這個值,它表示單個進程內存被限定在64m,即程序運行過程中實際只能使用64m內存,超出就會報OOM。(僅僅針對dalvik堆,不包括native堆)

dalvik.vm.heapsize=384m //heapsize參數表示單個進程可用的最大內存,

但如果存在heapgrowthlimit參數,則以heapgrowthlimit為准.
heapsize表示不受控情況下的極限堆,表示單個虛擬機或單個進程可用的最大內存。而android上的應用是帶有獨立虛擬機的,也就是每開一個應用就會打開一個獨立的虛擬機(這樣設計就會在單個程序崩潰的情況下不會導致整個系統的崩潰)。
注意:在設置了heapgrowthlimit的情況下,單個進程可用最大內存為heapgrowthlimit值。在android開發中,如果要使用大堆,需要在manifest中指定android:largeHeap為true,這樣dvm heap最大可達heapsize。

Android不同設備單個進程可用內存是不一樣的,可以查看/system/build.prop文件。

# This is a high density device with more memory, so larger vm heaps for it.
dalvik.vm.heapsize=24m

上面heapsize參數表示單個進程可用的最大內存,單如果存在如下參數:

dalvik.vm.heapgrowthlimit=16m

largeheaplimit參數表示單個進程內存被限定在16m,即程序運行過程中實際只能使用16m內存,不過有一個辦法可以解決,編輯AndroidManifest.xml中的Application節點,增加屬性largeheap="true"參數.

 

 // 應用程序最大可用內存  dalvik.vm.heapsize的值我的手機是256M
        long maxMemory = ((int) Runtime.getRuntime().maxMemory())/1024/1024;  
        //應用程序已獲得內存  dalvik.vm.heapgrowthlimit的值我的手機是25M
        long totalMemory = ((int) Runtime.getRuntime().totalMemory())/1024/1024;  
        //應用程序已獲得內存中未使用內存  
        long freeMemory = ((int) Runtime.getRuntime().freeMemory())/1024/1024; 
        
	        System.out.println("---> maxMemory="+maxMemory+"M,totalMemory="+totalMemory+"M,freeMemory="+freeMemory+"M");
	    Toast.makeText(MainActivity.this, "---> maxMemory="+maxMemory+"M,totalMemory="+totalMemory+"M,freeMemory="+freeMemory+"M", Toast.LENGTH_SHORT).show();

JAVA的內存管理
大家都知道,android應用層是由java開發的,android的davlik虛擬機與jvm也類似,只不過它是基於寄存器的。因此要了解android的內存管理就必須得了解java的內存分配和垃圾回收機制。
在java中,是通過new關鍵字來為對象分配內存的,而內存的釋放是由垃圾收集器(GC)來回收的,工程師在開發的過程中,不需要顯式的去管理內存。但是這樣有可能在不知不覺中就會浪費了很多內存,最終導致java虛擬機花費很多時間去進行垃圾回收,更嚴重的是造成JVM的OOM。因此,java工程師還是有必要了解JAVA的內存分配和垃圾回收機制。

 

1,內存結構

\

上面這張圖是JVM的結構圖,它主要四個部分組成:Class Loader子系統和執行引擎,運行時方法區和本地方法區,我們主要來看下RUNTIME DATA AREA區,也就是我們常說的JVM內存。從圖中可以看出,RUNTIMEDATA AREA區主要由5個部分組成:
Method Area:被裝載的class的元信息存儲在Method Area中,它是線程共享的
Heap(堆):一個java虛擬機實例中只存在一個堆空間,存放一些對象信息,它是線程共享的
Java棧: java虛擬機直接對java棧進行兩種操作,以幀為單位的壓棧和出棧(非線程共享)
程序計數器(非線程共享)
本地方法棧(非線程共享)

2,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分析下載下來的文件

\

關於MAT的使用可以參考:http://www.blogjava.net/rosen/archive/2010/06/13/323522.html
這位兄弟寫的比較詳細。

轉自:http://blog.csdn.net/xieqibao/article/details/6707519

android的內存優化看另一篇文章:

Android內存優化的幾種方案

 

3、為什麼會內存洩露(Memory Leak)?
android通過android虛擬機來管理內存,程序員只管申請內存創建對象,創建完不再需要關心怎麼釋放對象內存,一切由虛擬機幫你搞定,然而虛擬機回收對象是有條件的。這裡簡單敘述下java內存管理機制,java虛擬機維護著一張當前對象關系的object tree,當GC發生時,虛擬機會從GC Roots 開始去掃描當前的對象樹,發現通過任何reference chain(引用鏈)無法訪問某個對象的時候,該對象即被回收。名詞GC Roots正是分析這一過程的起點,例如JVM自己確保了對象的可到達性(那麼JVM就是GC Roots),所以GC Roots就是這樣在內存中保持對象可到達性的,一旦不可到達,即被回收。通常GC Roots是一個在current thread(當前線程)的call stack(調用棧)上的對象(例如方法參數和局部變量),或者是線程自身或者是system class loader(系統類加載器)加載的類以及native code(本地代碼)保留的活動對象。所以GC Roots是分析對象為何還存活於內存中的利器。知道了什麼樣的對象GC才會回收後,再來學習下對象引用都包含哪些吧。
Java中包含4種對象引用:
強引用: 通常我們編寫的代碼都是Strong Ref,eg :Person person = new Person("sunny");不管系統資源有多緊張,強引用的對象都絕對不會被回收,即使他以後不再用到。
軟引用:只要有足夠的內存,就一直保持對象。一般可用來實現緩存,通過java.lang.r.efSoftReference類實現。內存非常緊張的時候會被回收,其他時候不會被回收,所以在使用之前需要判空,從而判斷當前時候已經被回收了。
弱引用:通過WeakReference類實現,eg : WeakReference p = new WeakReference(new Person("Rain"));不管內存是否足夠,系統垃圾回收時必定會回收。
虛引用:不能單獨使用,主要是用於追蹤對象被垃圾回收的狀態。通過PhantomReference類和引用隊列ReferenceQueue類聯合使用實現。

4、為什麼會發生OOM(Out Of Memory)?
OOM:即OutOfMemoery,顧名思義就是指內存溢出了。之前我們知道Android的應用程序所能申請的最大內存都是有限的,OOM是指APP向系統申請內存的請求超過了應用所能有的最大閥值的內存,系統無法再分配多余的空間,就會造成OOM error。在Android平台下,除了之前所說的持續發生了內存洩漏(Memory Leak),累積到一定程度導致OOM的情況以外,也有一次性申請很多內存,比如說一次創建大的數組或者是載入大的文件如圖片的時候。實際中很多情況就是出現在圖片不當處理加載的時候。

5、常見的MemoryLeak分析
後來看到了更多的MemoryLeak相關的知識,有了更多的實踐經驗,
 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved