android--dalvik heap 浅析

原创 2015年07月08日 15:50:54

系统中可以在prop中配置dalvik堆的有关设定。具体设定由如下三个属性来控制

数据在system/build.prop文件里存储

-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里粗略看出一些原理:

 

  1.   
  2. static void *tryMalloc(size_t size)  
  3. {  
  4.     void *ptr;  
  5.   
  6.       
  7.     if (size >= gDvm.heapGrowthLimit) {  
  8.         LOGW("%zd byte allocation exceeds the %zd byte maximum heap size",  
  9.              size, gDvm.heapGrowthLimit);  
  10.         ptr = NULL;  
  11.         goto collect_soft_refs;  
  12.     }  
  13.   
  14. //TODO: figure out better heuristics  
  15. //    There will be a lot of churn if someone allocates a bunch of  
  16. //    big objects in a row, and we hit the frag case each time.  
  17. //    A full GC for each.  
  18. //    Maybe we grow the heap in bigger leaps  
  19. //    Maybe we skip the GC if the size is large and we did one recently  
  20. //      (number of allocations ago) (watch for thread effects)  
  21. //    DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other  
  22. //      (or, at least, there are only 0-5 objects swept each time)  
  23.   
  24.     ptr = dvmHeapSourceAlloc(size);  
  25.     if (ptr != NULL) {  
  26.         return ptr;  
  27.     }  
  28.   
  29.       
  30.     if (gDvm.gcHeap->gcRunning) {  
  31.           
  32.         dvmWaitForConcurrentGcToComplete();  
  33.         ptr = dvmHeapSourceAlloc(size);  
  34.         if (ptr != NULL) {  
  35.             return ptr;  
  36.         }  
  37.     }  
  38.       
  39.     gcForMalloc(false);  
  40.     ptr = dvmHeapSourceAlloc(size);  
  41.     if (ptr != NULL) {  
  42.         return ptr;  
  43.     }  
  44.   
  45.       
  46.     ptr = dvmHeapSourceAllocAndGrow(size);  
  47.     if (ptr != NULL) {  
  48.         size_t newHeapSize;  
  49.   
  50.         newHeapSize = dvmHeapSourceGetIdealFootprint();  
  51. //TODO: may want to grow a little bit more so that the amount of free  
  52. //      space is equal to the old free space + the utilization slop for  
  53. //      the new allocation.  
  54.         LOGI_HEAP("Grow heap (frag case) to "  
  55.                 "%zu.zuMB for %zu-byte allocation",  
  56.                 FRACTIONAL_MB(newHeapSize), size);  
  57.         return ptr;  
  58.     }  
  59.   
  60.       
  61. //TODO: wait for the finalizers from the previous GC to finish  
  62. collect_soft_refs:  
  63.     LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation",  
  64.             size);  
  65.     gcForMalloc(true);  
  66.     ptr = dvmHeapSourceAllocAndGrow(size);  
  67.     if (ptr != NULL) {  
  68.         return ptr;  
  69.     }  
  70. //TODO: maybe wait for finalizers and try one last time  
  71.   
  72.     LOGE_HEAP("Out of memory on a %zd-byte allocation.", size);  
  73. //TODO: tell the HeapSource to dump its state  
  74.     dvmDumpThread(dvmThreadSelf(), false);  
  75.   
  76.     return NULL;  
  77. }  

 

这里分为如下几个动作

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。其中有一个小段代码如下:

 

  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的代码如下:

 

 

  1. if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {  
  2.             dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();  
  3.         }  

这里经过jni调用,最终回来到heapsource.cpp中的dvmClearGrowthLimit函数中:

 

 

  1.   
  2. void dvmClearGrowthLimit()  
  3. {  
  4.     HS_BOILERPLATE();  
  5.     dvmLockHeap();  
  6.     dvmWaitForConcurrentGcToComplete();  
  7.     gHs->growthLimit = gHs->maximumSize;  
  8.     size_t overhead = oldHeapOverhead(gHs, false);  
  9.     gHs->heaps[0].maximumSize = gHs->maximumSize - overhead;  
  10.     gHs->heaps[0].limit = gHs->heaps[0].base + gHs->heaps[0].maximumSize;  
  11.     dvmUnlockHeap();  
  12. }  
这里会把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。



Heap Spray原理浅析

Heap Spray定义基本描述 Heap Spray并没有一个官方的正式定义,毕竟这是漏洞攻击技术的一部分。但是我们可以根据它的特点自己来简单总结一下。Heap Spray是在shellcode的...
  • QQ1084283172
  • QQ1084283172
  • 2015年08月05日 10:47
  • 1092

Heap Spray原理浅析

摘要:本文主要介绍Heap Spray的基本原理和特点、以及防范技术。 关键词:Heap Spray、溢出攻击、漏洞利用、堆溢出   Heap Spray定义基本描述 Heap...
  • zhou191954
  • zhou191954
  • 2014年09月03日 15:49
  • 460

Heap Spray原理浅析

转载自:http://blog.csdn.net/magictong/article/details/7391397 Heap Spray原理浅析 Magictong 2012/03   ...
  • u012410612
  • u012410612
  • 2013年10月15日 13:03
  • 535

Heap Spray原理浅析

Heap Spray原理浅析 分类: 计算机安全 汇编 common C++ Win322012-03-24 23:29 4736人阅读 评论(6) 收藏 举报 javascrip...
  • pi9nc
  • pi9nc
  • 2013年12月05日 14:26
  • 818

Heap Spray原理浅析

转自:http://blog.csdn.net/magictong/article/details/7391397 Heap Spray原理浅析 Magictong 2012/...
  • lixiangminghate
  • lixiangminghate
  • 2016年11月30日 20:59
  • 417

eclipse 里面heap 内存报告分析

无 论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方。 Android tools中的DDMS就带有一个很不错的内存监测工具Heap...
  • u011213711
  • u011213711
  • 2016年07月04日 14:12
  • 680

面试题思考:Stack和Heap的区别

堆和栈的区别
  • u014306011
  • u014306011
  • 2016年04月02日 15:30
  • 3353

stl中的heap使用

参加腾讯马拉松的时候,又一道题目需要用堆来维护数据,我居然不会用stl中的堆,只好到网上搜,真是往事不堪回首。。。 stl中的堆默认是最大堆,要想用最小堆的话,必须要在push_heap,pop_he...
  • lwfcgz
  • lwfcgz
  • 2013年04月04日 22:46
  • 7073

数据结构之Binary Heap(二叉堆)

数据结构之Binary Heap(二叉堆)1.Binary Heap的定义 二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:...
  • Mr_KkTian
  • Mr_KkTian
  • 2016年10月22日 15:11
  • 1348

stack与heap的关系与区别

stack:         具体地说,现代计算机(串行执行机制),都直接在代码底层支持栈的数据结构。这体现在,有专门的寄存器指向栈所在的地址,有专门的机器指令完成数据入栈出栈的操作。这种机制的特点...
  • ydonghao2
  • ydonghao2
  • 2013年10月25日 19:24
  • 2638
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android--dalvik heap 浅析
举报原因:
原因补充:

(最多只允许输入30个字)