android dalvik heap 浅析
来源:互联网 发布:如何查看ftp的端口号 编辑:程序博客网 时间:2024/05/01 09:57
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里粗略看出一些原理:
/* 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 finishcollect_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。
以上只是参照源码的个人理解,如果有什么错误的地方。欢迎指正
- android dalvik heap 浅析
- android dalvik heap 浅析
- android dalvik heap 浅析
- android--dalvik heap 浅析
- android dalvik heap 浅析
- android dalvik heap 浅析
- android dalvik heap 浅析
- android dalvik heap 浅析
- android dalvik heap 管理
- android dalvik heap管理,androiddalvik
- android dalvik heap 参数解析
- android dalvik浅析一
- 修改Android手机的dalvik-heap的大小
- Dalvik Heap Profiling
- heap in dalvik
- dalvik的Heap和Stack
- Heap Spray原理浅析
- Heap Spray原理浅析
- build/envsetup.sh的简介
- Android 漂亮的 Dialog (弹出框)
- HDOJ 3435 - A new Graph Game 无向图分割成若干哈密顿回路(二分图最小权匹配,最小费用最大流).
- delphi 读写文本文件
- QT4.5.2移植MC100环境搭建步骤
- android dalvik heap 浅析
- C#入门经典—第八章
- fpga分配引脚
- Android动画学习笔记-Android Animation
- SQL连接池
- HDU 1686
- jdk安装及环境变量的配置
- HDU1509-priority_queue
- win7防火墙开放某个端口