編輯:關於Android編程
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不受控情況下的極限堆大小,這個就是堆的最大值。不管它是不是受控的。這個值會影響非受控應用的dalvikheap 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裡粗略看出一些原理:
/* Try as hard as possible to allocate some memory. */ static void *tryMalloc(size_t size) { void *ptr; /* Don't try too hard if there's no way the allocation is * going to succeed. We have to collect SoftReferences before * throwing an OOME, though. */ if (size >= gDvm.heapGrowthLimit) { LOGW("%zd byte allocation exceeds the %zd byte maximum heap size", size, gDvm.heapGrowthLimit); ptr = NULL; goto collect_soft_refs; } //TODO: figure out better heuristics // There will be a lot of churn if someone allocates a bunch of // big objects in a row, and we hit the frag case each time. // A full GC for each. // Maybe we grow the heap in bigger leaps // Maybe we skip the GC if the size is large and we did one recently // (number of allocations ago) (watch for thread effects) // DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other // (or, at least, there are only 0-5 objects swept each time) ptr = dvmHeapSourceAlloc(size); if (ptr != NULL) { return ptr; } /* * The allocation failed. If the GC is running, block until it * completes and retry. */ if (gDvm.gcHeap->gcRunning) { /* * The GC is concurrently tracing the heap. Release the heap * lock, wait for the GC to complete, and retrying allocating. */ dvmWaitForConcurrentGcToComplete(); ptr = dvmHeapSourceAlloc(size); if (ptr != NULL) { return ptr; } } /* * Another failure. Our thread was starved or there may be too * many live objects. Try a foreground GC. This will have no * effect if the concurrent GC is already running. */ gcForMalloc(false); ptr = dvmHeapSourceAlloc(size); if (ptr != NULL) { return ptr; } /* Even that didn't work; this is an exceptional state. * Try harder, growing the heap if necessary. */ ptr = dvmHeapSourceAllocAndGrow(size); if (ptr != NULL) { size_t newHeapSize; newHeapSize = dvmHeapSourceGetIdealFootprint(); //TODO: may want to grow a little bit more so that the amount of free // space is equal to the old free space + the utilization slop for // the new allocation. LOGI_HEAP("Grow heap (frag case) to " "%zu.%03zuMB for %zu-byte allocation", FRACTIONAL_MB(newHeapSize), size); return ptr; } /* Most allocations should have succeeded by now, so the heap * is really full, really fragmented, or the requested size is * really big. Do another GC, collecting SoftReferences this * time. The VM spec requires that all SoftReferences have * been collected and cleared before throwing an OOME. */ //TODO: wait for the finalizers from the previous GC to finish collect_soft_refs: LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation", size); gcForMalloc(true); ptr = dvmHeapSourceAllocAndGrow(size); if (ptr != NULL) { return ptr; } //TODO: maybe wait for finalizers and try one last time LOGE_HEAP("Out of memory on a %zd-byte allocation.", size); //TODO: tell the HeapSource to dump its state dvmDumpThread(dvmThreadSelf(), false); return NULL; }
這裡分為如下幾個動作
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。其中有一個小段代碼如下:
if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, false)) { ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; }
如果解析到apk中設置了largeHeap,則在applicationinfo中添加FLAG_LARGE_HEAP標簽。之後會在ActivityThead.java中的handleBindApplication處理,這個函數非常重要,底層process fork好之後,會由這個函數把上層應用綁定過去。並且調用上層應用的入口點。其中處理largeHeap的代碼如下:
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) { dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); }
這裡經過jni調用,最終回來到heapsource.cpp中的dvmClearGrowthLimit函數中:
/* * Removes any growth limits. Allows the user to allocate up to the * maximum heap size. */ void dvmClearGrowthLimit() { HS_BOILERPLATE(); dvmLockHeap(); dvmWaitForConcurrentGcToComplete(); gHs->growthLimit = gHs->maximumSize; size_t overhead = oldHeapOverhead(gHs, false); gHs->heaps[0].maximumSize = gHs->maximumSize - overhead; gHs->heaps[0].limit = gHs->heaps[0].base + gHs->heaps[0].maximumSize; dvmUnlockHeap(); }
這裡會把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。
先上效果圖: Layout文件: 首先介紹兩種把資源裡的drawable轉成bitmap的方式 第一種: Bitma
最近需要編寫一個日期時間的桌面Widget用來關聯日歷程序,以前很少寫桌面Widget。對這方面技術不是很熟悉,今天花時間重新整理了一下,順便把編寫一個簡單時間日期程序過
知識點目錄 10.1 布局優化 10.1.1 Android UI渲染機制 10.1.2 避免Overdraw 10.1.3 優化布局層級 10.1.4 避免嵌套過多無用
今天給大家帶來的是僅僅使用一個TextView實現一個高仿京東、淘寶、唯品會等各種電商APP的活動倒計時。最近公司一直加班也沒來得及時間去整理,今天難得休息想把這個分享給