Android中的JVM如何追蹤Bitmap buffer的大小

http://oxygenplan.blogspot.sg/2011/02/androidjvmbitmap-buffer.html

在Android裡面,當app嘗試索取memory時,此時若process的memory使用量超過上限時,JVM會丟出out of memory的exception,我們可以在Heap.c裡面的dvmMalloc(size_t size, int flags)找到.
void* dvmMalloc(size_t size, int flags) {
...
ptr = tryMalloc(size);
...
if (ptr != NULL) {
...
} else {
...

 LOGE("Out of memory: Heap Size=%dKB, Allocated=%dKB, Bitmap Size=%dKB, Limit=%dKB",
            dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT, NULL, 0)/1024,
            dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0)/1024,
            dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0)/1024,
            gDvm.heapSizeMax / 1024);
...
}
...
}
但是本篇中,我們只關注於Bitmap裡面pixel buffer的使用量.從source code中可發現,VM是監控HS_EXTERNAL_BYTES_ALLOCATED的使用量,來控管Bitmap size.

我們寫一段簡單的sample code, 看看HS_EXTERNAL_BYTES_ALLOCATED的memory使用量的變化.
public class Foo {
     public void monitorBitmap() {
          Bitmap src = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
          ...
          src.recycle();
     }
}
在這個sample code的monitorBitmap()中只做了兩件事情:
1. new一個Bitmap,
2. 回收它(recycle()).
首先,trace create Bitmap object 的過程,
1. createBitmap(int width, int height, Config config); [Bitmap.java]
2. nativeCreate(int[] colors, int offset,  int stride, int width, int height, int nativeConfig, boolean mutable); [Bitmap.java]
---JNI------------------------------------------------------
3. Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, int offset, int stride, int width, int height, SkBitmap::Config config, jboolean isMutable); [Bitmap.cpp]
4. GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true); [Graphics.cpp]
5.1. JNIEnv::CallBooleanMethod(gVMRuntime_singleton, gVMRuntime_trackExternalAllocationMethodID, jsize); [Graphics.cpp]
5.2. void* addr = sk_malloc_flags(size, 0); [Graphics.cpp]
5.3. SkPixelRef* pr = new AndroidPixelRef(env, addr, size, ctable, reportSizeToVM); [Graphics.cpp]
5.4. bitmap->setPixelRef(pr)->unref(); [Graphics.cpp]
在步驟5.1., JVM紀錄Bitmap的size,並追蹤它. 5.2.,5.3. malloc pixel buffer同時放入SkPixelRef object中以方便控管. SkPixelRef繼承SkRefCnt,因此使用了reference count的技巧,可以偵測有多少個object參考到它. 5.4. 將SkPixelRef放入SkBitmap, 同時將先前Bitmap object內部所持有的SkPixelRef object unref().
最後,我們來看當Bitmap object被recycle()時,做了哪些處理:


1. recycle(); [Bitmap.java]
2. nativeRecycle(int nativeBitmap); [Bitmap.java]
---JNI------------------------------------------------------
3. Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap); [Bitmap.cpp]
4. SkBitmap::setPixels(NULL, NULL); [SkBitmap.cpp]
5. SkBitmap::freePixels(); [SkBitmap.cpp]
6. AndroidPixelRef::unref(); [Graphics.cpp]
7. AndroidPixelRef::~AndroidPixelRef(); [Graphics.cpp]
8. JNIEnv::CallVoidMethod(gVMRuntime_singleton, gVMRuntime_trackExternalFreeMethodID, jsize); [Graphics.cpp]
在步驟8, JVM移除先前所記載的pixel buffer size的紀錄.
由上面的範例中,我們可以得知JVM是如何記錄與追蹤Bitmap size的大小.

Dalvik:

进行数据统计,然后调用GC。其实还是全部靠Bitmap自己管理。

猜你喜欢

转载自qianjigui.iteye.com/blog/1558477
今日推荐