转载:
viclee分享,是一种态度 - Android Dalvik虚拟机内存分配问题
简介
之前遇到一个android上图片加载不出来的问题,在三星的note3上极容易出现,而在nexus 4上则很难出现。后来通过DDMS观察发现,是某一个模块一直内存泄漏使得内存接近上限,导致一些大图(需要的内存比较大)申请内存失败,一直加载不出来。为什么会出现这种状况呢?
分析
通过getprop拿到两个手机上dalvik虚拟机的参数,三星的note3上的dalvik.vm.heapgrowthlimit为64M,而nexus4上的dalvik.vm.heapgrowthlimit为192M,后者是前者的三倍。也就是说note3上存在内存泄漏的时候,虚拟机的内存很容易就达到64M的上限,而在nexus4上要达到192M还是很难的,这也就解释了前面的现象。
参数
说到这里,我们来看看虚拟机的几个重要参数的意义。
dalvik.vm.heapstartsize
堆分配的初始大小,调整这个值会影响到应用的流畅性和整体ram消耗。这个值越小,系统ram消耗越慢,但是由于初始值较小,一些较大的应用需要扩张这个堆,从而引发gc和堆调整的策略,会应用反应更慢。相反,这个值越大系统ram消耗越快,但是程序更流畅。
dalvik.vm.heapgrowthlimit
极限堆大小,dvm heap是可增长的,但是正常情况下dvm heap的大小是不会超过dalvik.vm.heapgrowthlimit的值。如果受控的应用dvm heap size超过该值,则将引发oom。
dalvik.vm.heapsize
使用大堆时,极限堆大小。一旦dalvik heap size超过这个值,直接引发oom。在android开发中,如果要使用大堆,需要在manifest中指定android:largeHeap为true。这样dvm heap最大可达dalvik.vm.heapsize。
[dalvik.vm.heaptargetutilization]: [0.75]
可以设定内存利用率的百分比,当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。
关系
上面的几个参数是与虚拟机的内存分配相关的,虚拟机的内存分配过程是下面这样的:
- 1.首先判断一下需要申请的size是不是过大,如果申请的size超过了堆的最大限制,则转入步骤6
- 2.尝试分配,如果成功则返回,失败则转入步骤3
- 3.判断是否gc正在进行垃圾回收,如果正在进行则等待回收完成之后,尝试分配。如果成功则返回,失败则转入步骤4
- 4.自己启动gc进行垃圾回收,这里gcForMalloc的参数是false。所以不会回收软引用,回收完成后尝试分配,如果成功则返回,失败则转入步骤5
- 5.调用dvmHeapSourceAllocAndGrow尝试分配,这个函数会扩张堆。所以heap startup的时候可以给一个比较小的初始堆,实在不够用再调用它进行扩张
- 6.进入回收软引用阶段,这里gcForMalloc的参数是ture,所以需要回收软引用。然后调用dvmHeapSourceAllocAndGrow尝试分配,如果失败则抛出OOM。