谈到Bitmap就必须和Android虚拟机内存扯上关系。在Android开发中,内存使用一直是围绕Bitmap开发的难点。虽然Java有专门的垃圾回收机制(GC),但是在Bitmap使用中,常常会遇到过OOM(out of memory)异常,相信有Android多媒体开发经验的朋友体会尤为深刻。
首先来分析一下OOM的原因,当我们使用BitmapFactory来decode一张3.5M大小的图片(3456*2304),我们decode出来的Bitmap的大小是多少呢?
Bitmap大小计算公式: Size = image.width * image.height * Config
(Config 参数为图片的编码器,常见的图片编译器有 ALPHA_8、RGB_565、ARGB_4444(Deprecated)、ARGB_8888)
RGB_565解码器占用2 byte ARGB_8888 解码器占用4byte
当图片采用ARGB_8888编码器时,Config为4,那么decode后的Bitmap大小为:3456 * 2304 * 4,换算成M为30.375M,My God整整是原来图片的8.6785倍,因此当我们使用Bitmap时稍有不慎,造成OOM简直成了理所当然了。
难道编写Android的大牛们没有考虑到这个问题?
答案肯定是考虑到了的。在阐述接下来的问题之前,要给大家洗洗脑。很多人都认为Android应用所占用的内存就是虚拟机(Dalvik)所占用的内存。其实Android应用所占用的内存由Dalvik虚拟机内存和Native Memory内存组成。因此,当我们在进行多媒体开发的时候遇到OOM时,Java层代码已经做到perfect了(代码优化到极致),还是存在OOM异常的时候。可以利用Native Memory(本地内存)来解决OOM异常。
利用Native Memory?
我没听错吧?Davik 虚拟机内存和 C/C++的Native Memory共享?真是什么高难度技术,研究了半天源码,还是没有看出大牛们是怎么实现。具体实现的我们先放一边,(如果大家对内存共享感兴趣的话,可以去研究一下,顺便告诉我以下,在此先谢过了)我们的目的是怎样使用Native Memory内存。换句话说我们需要怎样将Bitmap所占用的内存挪到Native Memory内存中,这才是我们的重点。
查看应用占用的内存(Dalvik 虚拟机和Native Memory)大小的方式如下所示:
# adb shell dumpsys meminfo com.jony.actionbar
首先我们来看看使用Dalvik虚拟机来的decode一张Bitmap所占用的内存大小。
使用图片信息: Storage: 3.5M图片(3456*2304)
网上有很多人说使用decodeStream()方法,不需要使用Java层decode Bitmap,因此可以节省Java层虚拟机的内存。我不知道这些人是凭空想象,还有有什么证据来说明他们的结论。根据我的实验以及源码的分析,BitmapFactory的decode方法都是调用的Java的Native方法。因此网上的这种说法正确性还有待考证。
方法一:
AssetManager am = getAssets(); InputStream is = am.open("high_pixel_img.jpg"); Bitmap bitmap = BitmapFactory.decodeStream(is);
Dalvik虚拟机占用的内存如图3-1所示:
(备注:其中红色标记的为当前Dalvik虚拟机所占内存)
使用#adb shell dumpsys meminfo com.jony.bitmaptest 命令查看Dalvik虚拟机内存和Native memory使用情况如图3-2所示:
图 3-2
方法二:
try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Config.ARGB_8888; options.inPurgeable = true;//允许可清除 options.inInputShareable = true;// 以上options的两个属性必须联合使用才会有效果 AssetManager am = getAssets(); InputStream is = am.open("high_pixel_img.jpg"); Bitmap bitmap = BitmapFactory.decodeStream(is,null,options); imageView.setImageBitmap(bitmap); } catch (IOException e) { e.printStackTrace(); }
使用#adb shell dumpsys meminfo com.jony.bitmaptest 命令查看Dalvik虚拟机内存和Native memory使用情况如图所示:
图 3-4
结合以上信息可以分析出:采用方法一Decode一张图片的时候Bitmap占用的是Dalvik虚拟机的内存;采用方法二Decode一张图片的时候Bitmap占用的Native memory的内存空间。因此在使用Bitmap的时候,可以根据业务的需求采用不同的内存占用方式,完美的解决OOM问题。