1. 程式人生 > >Android Dalvik虛擬機器記憶體分配問題

Android Dalvik虛擬機器記憶體分配問題

       之前遇到一個android上圖片載入不出來的問題,在三星的note3上極容易出現,而在nexus 4上則很難出現。後來通過DDMS觀察發現,是某一個模組一直記憶體洩漏使得記憶體接近上限,導致一些大圖(需要的記憶體比較大)申請記憶體失敗,一直載入不出來。為什麼會出現這種狀況呢?

      通過getprop拿到兩個手機上dalvik虛擬機器的引數,三星的note3上的dalvik.vm.heapgrowthlimit為64M,而nexus4上的dalvik.vm.heapgrowthlimit為192M,後者是前者的三倍。也就是說note3上存在記憶體洩漏的時候,虛擬機器的記憶體很容易就達到64M的上限,而在nexus4上要達到192M還是很難的,這也就解釋了前面的現象。

      說到這裡,我們來看看虛擬機器的幾個重要引數的意義。

      dalvik.vm.heapstartsize  

     堆分配的初始大小,調整這個值會影響到應用的流暢性和整體ram消耗。這個值越小,系統ram消耗越慢,但是由於初始值較小,一些較大的應用需要擴張這個堆,從而引發gc和堆調整的策略,會應用反應更慢。相反,這個值越大系統ram消耗越快,但是程式更流暢。

     dalvik.vm.heapgrowthlimit       

     極限堆大小,dvm heap是可增長的,但是正常情況下dvm heap的大小是不會超過dalvik.vm.heapgrowthlimit

的值。如果受控的應用dvm heap size超過該值,則將引發oom。

    dalvik.vm.heapsize 

    使用大堆時,極限堆大小。一旦dalvik heap size超過這個值,直接引發oom。在android開發中,如果要使用大堆,需要在manifest中指定android:largeHeap為true。這樣dvm heap最大可達dalvik.vm.heapsize。

    [dalvik.vm.heaptargetutilization]: [0.75] 可以設定記憶體利用率的百分比,當實際的利用率偏離這個百分比的時候,虛擬機器會在GC的時候調整堆記憶體大小,

讓實際佔用率向個百分比靠攏。

   上面的幾個引數是與虛擬機器的記憶體分配相關的,虛擬機器的記憶體分配過程是下面這樣的:

1  首先判斷一下需要申請的size是不是過大,如果申請的size超過了堆的最大限制,則轉入步驟6

2  嘗試分配,如果成功則返回,失敗則轉入步驟3

3  判斷是否gc正在進行垃圾回收,如果正在進行則等待回收完成之後,嘗試分配。如果成功則返回,失敗則轉入步驟4

4  自己啟動gc進行垃圾回收,這裡gcForMalloc的引數是false。所以不會回收軟引用,回收完成後嘗試分配,如果成功則返回,失敗則轉入步驟5

5  呼叫dvmHeapSourceAllocAndGrow嘗試分配,這個函式會擴張堆。所以heap startup的時候可以給一個比較小的初始堆,實在不夠用再呼叫它進行擴張

6  進入回收軟引用階段,這裡gcForMalloc的引數是ture,所以需要回收軟引用。然後呼叫dvmHeapSourceAllocAndGrow嘗試分配,如果失敗則丟擲OOM。