1. 程式人生 > >android dalvik heap 引數解析

android dalvik heap 引數解析

android 系統中可以在prop中配置dalvik堆的有關設定。具體設定由如下三個屬性來控制

-dalvik.vm.heapstartsize            

     堆分配的初始大小,調整這個值會影響到應用的流暢性和整體ram消耗。這個值越小,系統ram消耗越慢,

但是由於初始值較小,一些較大的應用需要擴張這個堆,從而引發gc和堆調整的策略,會應用反應更慢。

相反,這個值越大系統ram消耗越快,但是程式更流暢。

-dalvik.vm.heapgrowthlimit       

     受控情況下的極限堆(僅僅針對dalvik堆,不包括native堆)大小,dvm heap是可增長的,但是正常情況下

dvm heap的大小是不會超過dalvik.vm.heapgrowthlimit的值(非正常情況下面會詳細說明)。這個值控制那

些受控應用的極限堆大小,如果受控的應用dvm heap size超過該值,則將引發oom(out of memory)。

-dalvik.vm.heapsize 

    不受控情況下的極限堆大小,這個就是堆的最大值。不管它是不是受控的。這個值會影響非受控應用的dalvik

heap size。一旦dalvik heap size超過這個值,直接引發oom。

    用他們三者之間的關係做一個簡單的比喻:分配dalvik heap就好像去食堂打飯,有人飯量大,要吃三碗,有人飯量小,連一碗都吃不完。如果食堂按照三碗的標準來給每個人打飯,那絕對是鋪張浪費,所以食堂的策略就是先打一碗,湊合吃,不夠了自己再來加,設定堆大小也是一樣,先給一個合理值,湊合用,自己不夠了再跟系統要。食堂畢竟是做買賣的,如果很多人明顯吃不了那麼多,硬是一碗接著一碗。為了制止這種不合理的現象,食堂又定了一個策略,一般人就只能吃三碗。但是如果虎背熊腰的大漢確實有需要,可以吃上五碗,超過五碗就不給了(太虧本了)。

開始給一碗                                            對應       dalvik.vm.heapstartsize 

一般人最多吃三碗                                 對應       dalvik.vm.heapgrowthlimit

虎背熊腰的大漢最多能吃五碗              對應       dalvik.vm.heapsize

    在android開發中,如果要使用大堆。需要在manifest中指定android:largeHeap為true。這樣dvm heap最大可達dalvik.vm.heapsize。其中分配過程,可以在heap.cpp裡粗略看出一些原理:

[cpp] view plaincopyprint?
  1. /* Try as hard as possible to allocate some memory. 
  2.  */
  3. staticvoid *tryMalloc(size_t size)  
  4. {  
  5.     void *ptr;  
  6.     /* Don't try too hard if there's no way the allocation is 
  7.      * going to succeed.  We have to collect SoftReferences before 
  8.      * throwing an OOME, though. 
  9.      */
  10.     if (size >= gDvm.heapGrowthLimit) {  
  11.         LOGW("%zd byte allocation exceeds the %zd byte maximum heap size",  
  12.              size, gDvm.heapGrowthLimit);  
  13.         ptr = NULL;  
  14.         goto collect_soft_refs;  
  15.     }  
  16. //TODO: figure out better heuristics
  17. //    There will be a lot of churn if someone allocates a bunch of
  18. //    big objects in a row, and we hit the frag case each time.
  19. //    A full GC for each.
  20. //    Maybe we grow the heap in bigger leaps
  21. //    Maybe we skip the GC if the size is large and we did one recently
  22. //      (number of allocations ago) (watch for thread effects)
  23. //    DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
  24. //      (or, at least, there are only 0-5 objects swept each time)
  25.     ptr = dvmHeapSourceAlloc(size);  
  26.     if (ptr != NULL) {  
  27.         return ptr;  
  28.     }  
  29.     /* 
  30.      * The allocation failed.  If the GC is running, block until it 
  31.      * completes and retry. 
  32.      */
  33.     if (gDvm.gcHeap->gcRunning) {  
  34.         /* 
  35.          * The GC is concurrently tracing the heap.  Release the heap 
  36.          * lock, wait for the GC to complete, and retrying allocating. 
  37.          */
  38.         dvmWaitForConcurrentGcToComplete();  
  39.         ptr = dvmHeapSourceAlloc(size);  
  40.         if (ptr != NULL) {  
  41.             return ptr;  
  42.         }  
  43.     }  
  44.     /* 
  45.      * Another failure.  Our thread was starved or there may be too 
  46.      * many live objects.  Try a foreground GC.  This will have no 
  47.      * effect if the concurrent GC is already running. 
  48.      */
  49.     gcForMalloc(false);  
  50.     ptr = dvmHeapSourceAlloc(size);  
  51.     if (ptr != NULL) {  
  52.         return ptr;  
  53.     }  
  54.     /* Even that didn't work;  this is an exceptional state. 
  55.      * Try harder, growing the heap if necessary. 
  56.      */
  57.     ptr = dvmHeapSourceAllocAndGrow(size);  
  58.     if (ptr != NULL) {  
  59.         size_t newHeapSize;  
  60.         newHeapSize = dvmHeapSourceGetIdealFootprint();  
  61. //TODO: may want to grow a little bit more so that the amount of free
  62. //      space is equal to the old free space + the utilization slop for
  63. //      the new allocation.
  64.         LOGI_HEAP("Grow heap (frag case) to "
  65.                 "%zu.%03zuMB for %zu-byte allocation",  
  66.                 FRACTIONAL_MB(newHeapSize), size);  
  67.         return ptr;  
  68.     }  
  69.     /* Most allocations should have succeeded by now, so the heap 
  70.      * is really full, really fragmented, or the requested size is 
  71.      * really big.  Do another GC, collecting SoftReferences this 
  72.      * time.  The VM spec requires that all SoftReferences have 
  73.      * been collected and cleared before throwing an OOME. 
  74.      */
  75. //TODO: wait for the finalizers from the previous GC to finish
  76. collect_soft_refs:  
  77.     LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation",  
  78.             size);  
  79.     gcForMalloc(true);  
  80.     ptr = dvmHeapSourceAllocAndGrow(size);  
  81.     if (ptr != NULL) {  
  82.         return ptr;  
  83.     }  
  84. //TODO: maybe wait for finalizers and try one last time
  85.     LOGE_HEAP("Out of memory on a %zd-byte allocation.", size);  
  86. //TODO: tell the HeapSource to dump its state
  87.     dvmDumpThread(dvmThreadSelf(), false);  
  88.     return NULL;  
  89. }  

這裡分為如下幾個動作

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

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

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

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

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

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

如果設定了largeHeap,具體流程從解析apk開始,原始碼位於PackagePaser.java中,其中parseApplication函式負責解析apk。其中有一個小段程式碼如下:

[java] view plaincopyprint?
  1. if (sa.getBoolean(  
  2.               com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,  
  3.               false)) {  
  4.           ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;  
  5.       }  

如果解析到apk中設定了largeHeap,則在applicationinfo中新增FLAG_LARGE_HEAP標籤。之後會在ActivityThead.java中的handleBindApplication處理,這個函式非常重要,底層process fork好之後,會由這個函式把上層應用繫結過去。並且呼叫上層應用的入口點。其中處理largeHeap的程式碼如下: [java] view plaincopyprint?
  1. if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {  
  2.             dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();  
  3.         }  

這裡經過jni呼叫,最終回來到heapsource.cpp中的dvmClearGrowthLimit函式中: [cpp] view plaincopyprint?
  1. /* 
  2.  * Removes any growth limits.  Allows the user to allocate up to the 
  3.  * maximum heap size. 
  4.  */
  5. void dvmClearGrowthLimit()  
  6. {  
  7.     HS_BOILERPLATE();  
  8.     dvmLockHeap();  
  9.     dvmWaitForConcurrentGcToComplete();  
  10.     gHs->growthLimit = gHs->maximumSize;  
  11.     size_t overhead = oldHeapOverhead(gHs, false);  
  12.     gHs->heaps[0].maximumSize = gHs->maximumSize - overhead;  
  13.     gHs->heaps[0].limit = gHs->heaps[0].base + gHs->heaps[0].maximumSize;  
  14.     dvmUnlockHeap();  
  15. }  
         這裡會把HeapSource的growthLimit設定為maximumSize,說簡單點就是把growthLimit有原來dalvik.vm.heapgrowthlimit的值調整為dalvik.vm.heapsize。不過分配的時候判斷oom的依據是根據heap中的maximumSize來決定。這裡不得不說一下HeapSource的兩個堆了,heaps[]陣列中有兩個堆。簡單來講,0號堆是可用堆,是開發給上層使用的。1號堆是fork的時候從zygote程序直接複製過來的,這個是死的,不會由dvm開放給上層使用。overhead標明瞭堆中已經分配可多少(包括0號堆和1號堆)。所以上層能分配打的最大使用量為 gHs->maxmumSize - overhead。

相關推薦

android dalvik heap 引數解析

android 系統中可以在prop中配置dalvik堆的有關設定。具體設定由如下三個屬性來控制 -dalvik.vm.heapstartsize                  堆分配的初始大小,調整這個值會影響到應用的流暢性和整體ram消耗。這個值越小,系統r

android dalvik heap 淺析

android 系統中可以在prop中配置dalvik堆的有關設定。具體設定由如下三個屬性來控制 -dalvik.vm.heapstartsize                  堆分配的初始大小,調整這個值會影響到應用的流暢性和整體ram消耗。這個值越小,系統ram

Android Dalvik VM GC options 命令控制引數

} else if (strncmp(argv[i], "-Xgc:", 5) == 0) { //In VM thread, there is a register map for marking each stack item's status whether it is an object o

Android中的DrawRect()引數解析

官方文件中的定義: drawRect(float left, float top, float right, float bottom, Paint paint) Draw the specif

Android OTA升級包製作指令碼詳解(一,引數解析

寫在前面:     “build/tools/releasetools/ota_from_target_files  -u lk.bin  -n target.zip update.zip”這是製作整包的命令,很顯然這裡支援lk升級。本系列博文主要對該命令的執行流程及原理進

Android屬性動畫完全解析(上),初識屬性動畫的基本用法

fcm 操作 fad 擴展性 改變 內部使用 如果 轉載 @override 轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/43536355 在手機上去實現一些動畫效果算是件比較炫酷的事情,因此Andr

Android Dalvik虛擬機和ART虛擬機對比

x文件 開始 過程 優秀 clas 編譯 apk 但是 好的 1.概述  Android4.4以上開始使用ART虛擬機,在此之前我們一直使用的Dalvik虛擬機,那麽為什麽Google突然換了Android運行的虛擬機呢?答案只有一個:ART虛擬機更優秀。 2.Dalvik

Android ToolBar 使用完全解析

都是 主題 image 需要 oid primary 調用 blank ast ToolBar簡介 ToolBar是Android 5.0推出的一個新的導航控件用於取代之前的ActionBar,由於其高度的可定制性、靈活性、具有Material Design風格等優點,

Android源代碼解析之(六)-->Log日誌

static 同學 ons ets urn append oct source for 轉載請標明出處:一片楓葉的專欄 首先說點題外話,對於想學android framework源代碼的同學,事實上能夠在github中fork一份,詳細地址:p

Android源代碼解析之(四)-->HandlerThread

轉載 detail dcl red tag msg click 創建 tor 轉載請標明出處:一片楓葉的專欄 上一篇文章中我們解說了AsyncTast的基本使用以及實現原理,我們知道AsyncTask內部是通過線程池和Handler實現的。通過

以芯片直讀方式得到的Android全盤鏡像解析——DOS分區

xtend gpt 裏的 per 記錄 style 工作 計算 區號   最近得到了一個依舊用芯片直讀方式得到的Android全盤鏡像,這次是一個紅米手機的鏡像,和之前的鏡像不同,這次的分區類型的DOS分區,這裏說明一下,算是對之前那篇記錄的補充。   首先要糾正一下我的一

Android源代碼解析之(十三)-->apk安裝流程

solved 就是 activity 文章 空間不夠 orien gpo tpm systems 轉載請標明出處:一片楓葉的專欄 上一篇文章中給大家分析了一

Android源代碼解析之(七)-->LruCache緩存類

access ref trie ber tro double prot 推斷 rate 轉載請標明出處:一片楓葉的專欄 android開發過程中常常會用到緩

Android懸浮窗原理解析(Window)[源碼]

tco inflate 情況 tint input tdi scree list 接收 懸浮窗,在大多數應用中還是很少見的,目前我們接觸到的懸浮窗,差不多都是一些系統級的應用軟件,例如:360安全衛士,騰訊手機管家等;在某些服務行業如金融,餐飲等,也會在應用中添加懸浮窗,例

Android 中可變引數的使用 如:int...

每天積累一點點,時間久了,你就是大牛了     以前沒接觸過可變引數,見到就覺得挺新鮮的,特此記錄一下和大家分享。     1.可變引數的表示方式是物件後面加三個點(Object...),可以是 int...

URLParser:很實用的URL引數解析器(JAVA程式碼中方便獲取QueryString中的get引數

很實用的URL引數解析器(JAVA程式碼中方便獲取QueryString中的get引數) package com.kaishustory.quick.commons.text; import java.io.UnsupportedEncodingException; import

【輸出文件】 Android 6 USB 模組解析

          USB模組解析 簡介 主要完成USB 功能的切換和狀態的更新。通過接受kernel傳送過來的event訊息來確定USB狀態的切換並向外界傳送廣播訊息。  

SpringMVC自動封裝List物件——自定義引數解析

  前臺傳遞的引數為集合物件時,後臺Controller希望用一個List集合接收資料。   原生SpringMVC是不支援,Controller引數定義為List型別時,接收引數會報如下錯誤: org.springframework.beans.BeanInstantiationException

Android版DesiredCapabilities引數配置

前言 每一個App測試都應指定是在什麼平臺下,那個裝置中執行那個App,而在Appium中主要是通過DesiredCapabilities來配置的。 DesiredCapabilities的作用,負責啟動服務時的引數配置;DesiredCapabilities的本質是key/value的物件。 &nbs

Android中Context引數解釋

 context的作用,就是android應用連線service的橋樑。 比如Activity中有經常會有可能呼叫到系統的service,使用getSystemService()方法,這個方法調到最後,實際上是呼叫的ContextImpl的getSystemSer