在android开发过程中,经常会遇到由Bitmap引起的内存溢出,今天和大家分享一下我解决内存溢出的一些方法。
一、图片加载到内存中所占的空间会比实际大小大
首先我们要知道我们在应用中用到的png或者jpg的图片都是经过压缩的,当被解码器解析出来加载到内存中时,图片所占的内存是原来的几倍甚至是十几倍。
我们可以先看个例子,pic1是张1M的jpg图片,加载到内存中占用了7.9M的内存:
上面用到了android DDMS中的内存监测工具,关于该工具的使用,可以参考下面的文章:
http://www.open-open.com/lib/view/open1340337547237.html
二、如何查看每个应用的最大内存
我们知道系统给每个应用分配了最大内存,当内存占用超过这个值时,就会报OOM(out of memory)的错误。我们如何查看这个值呢?Java提供了Runtime这个类,我们可以这样来获取应用的最大内存值:Runtime.getRuntime().maxMemory(),注:VMRuntime.getRuntime()这个东西在android 4.0及以上的环境中都找不到了。
如果上面返回的数是16M(不同的设备,最大内存不同),那我们用语句ByteArrayBuffer array = new ByteArrayBuffer(17*1024*1024)分配一个17M的Buffer ,就会报OOM异常:
我们还可以用命令getprop | grep heap来获取,输入命令之后回查到上述几个结果
[dalvik.vm.heapstartsize]: [8m]:给进程分配的起始heap=8m
[dalvik.vm.heapgrowthlimit]: [64m]:进程最大可分配到64m
[dalvik.vm.heapsize]: [256m]:单个虚拟机可分配的最大内存=256m
heapstartsize是初始化是给进程分配的内存,heapgrowthlimit是默认情况下可分配给单个进程的内存上限。Android可以再AndroidManifest.xml文件中配置:
android:largeHeap="true"
这样可分配给单个进程的内存上限就变成了heapsize的大小
上述参数是在/system/build.prop文件中配置的,这些参数都是可以修改的,具体修改方法见博客:
http://blog.csdn.net/cjj7905150/article/details/19758335
三、解析图片时的Options参数
我们在调用BitmapFactory的decodeResource (Resources res, int id,BitmapFactory.Options opts)方法时,可以传入Options参数。图片解析器会根据该参数的不同选项来执行不同的操作。
inBitmap,传入一个已经被解析的bitmap,这样就会复用该bitmap的内存空间,传入的bitmap的inSampleSize一定要为1,否则会报错。
inJustDecodeBounds,顾名思义,仅仅获取图片的宽高,而不解析其内容。
inPreferredConfig有四个值,分别是Config.ALPHA_8,Config.ARGB_4444,Config.ARGB_8888,Config.RGB_565。默认是Config.ARGB_8888,8位存储一个色彩通道,一个像素点占4个字节,Config.RGB_565是分别用5个bit位存储红色通道和蓝色通道,6个bit位存储绿色通道,没有alpha通道。对于色彩度变化不大且没有透明的图片,我们应Config.RGB_565的方式来存储,这样会比Config.ARGB_8888节省一半的空间(图片质量会有下降,大家自己看能不能接受)。
inPurgeable,若设置为true,系统在内存不够时,会将该bitmap的内存释放掉。如果要重新使用,就会重新解析,该属性能有效的缓解内存溢出的问题,但对性能会有一定的影响。
inSampleSize,该值>=1,解析器解析出originwidth/inSampleSize,originheight/inSampleSize大小的图片,结合inJustDecodeBounds属性,可以实现高效的图片缩放,网上有很多例子,在此不详述了。
四、java内存分析工具MAT的使用
MAT是一个很好的监测分析Java程序内存溢出的工具,具体使用参见博文:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/