Android4.0 输出分辨率改成1280*720后,出现Out of Memory

Android4.0 输出分辨率改为1280*720后,出现Out of Memory
1、出现这个问题的原因是由于Bitmap decode 引发的,我们知道,android程序内存一般限制在16M,当然也有24M的,而android程序内存被分为2部分:native和dalvik:dalvik就是我们平常说的java堆,我们创建的对象是在这里面分配的,而bitmap是直接在native上分配的,对于内存的限制是native+dalvik不能超过最大限制。

用以下命令可以查看程序的内存使用情况:

dumpsys meminfo 程序的包名或者进程id
 多数时候,发生OOM 都是在做一些跟图片相关的操作,以下提出一些建议尽量可以减少这种情况的发生:
decode bitmap 的时候,尽量配置下Options,例如:inSameSize
Bitmap使用完以后,调用 bitmap.recycle()来释放内存
如果应用是基于图片的应用,尽量采用LazyLoad和DymanicRecycle

decode bitmap 的时候,将decode代码 try catch 出来,catch oom error,避免程序crash,可以在catch里面做一些释放内存操作


2、关于Android的Native内存和Dalvik内存

1)、Dalvik内存:

每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。
很多人认为Dalvik虚拟机是一个Java虚拟机,因为Android的编程语言恰恰就是Java语言。但是这种说法并不准确,因为 Dalvik虚拟机并不是按照Java虚拟机的规范来实现的,两者并不兼容;
同时还要两个明显的不同:

(1)、Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的文件格式DEX(Dalvik Executable)。

(2)、在Java SE程序中的Java类会被编译成一个或者多个字节码文件(.class)然后打包到JAR文件,而后Java虚拟机会从相应的CLASS文件和JAR文件中获取相应的字节码;Android应用虽然也是使用Java语言进行编程,但是在编译成CLASS文件后,还会通过一个工具(dx)将应用所有的 CLASS文件转换成一个DEX文件,而后Dalvik虚拟机会从其中读取指令和数据。

2)、Dalvik虚拟机的简介:

Dalvik虚拟机主要是完成对象生命周期的管理,堆栈的管理,线程管理,安全和异常的管理,以及垃圾回收等等重要功能。
Dalvik虚拟机的主要特征Dalvik虚拟机非常适合在移动终端上使用,相对于在桌面系统和服务器系统运行的虚拟机而言,它不需要很快的CPU速度和大量的内存空间。
Dalvik虚拟机有如下几个主要特征:

(1)、专有的DEX文件格式
DEX是Dalvik虚拟机专用的文件格式,而问什么弃用已有的字节码文件(CLASS文件)而采用新的格式呢?一个应用中会定义很多类,编译完成后即会有很多相应的CLASS文件,CLASS文件间会有不少冗余的信息;而DEX文件格式会把所有的 CLASS文件内容整合到一个文件中。这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。

(2)、增加了新的操作码的支

(3)、文件结构尽量简洁,使用等长的指令,借以提高解析速度

(4)、尽量扩大只读结构的大小,借以提高跨进程的数据共享


3、如何修改Android应用程序的默认最大内存值:

Android应用程序的默认最大内存值为16M,有些应用程序可能会出现内存溢出,譬如ERROR/AndroidRuntime(264):java.lang.OutOfMemoryError: bitmap size exceeds VM budget
除了要检查修正代码之外,还可以考虑修改Android应用程序的默认最大内存值。
修改应用程序的默认最大内存有2种方法:

1)、修改代码,适用于自己编译烧机:
当应用程序分配内存时,会调用到dalvik/vm/alloc/HeapSource.c中的dvmTrackExternalAllocation()方法,继而调用到externalAllocPossible()方法,该方法要求当前堆已使用的大小(由currentHeapSize和hs->externalBytesAllocated构成)加上我们需要再次分配的内存大小不能超过堆的最大内存值,如果超过就会报错。 
有两个地方决定了一个堆的最大内存:

(1)、dalvik/vm/Init.cpp中的 

gDvm.heapSizeMax = 16 * 1024 * 1024;    // Spec says 75%physical mem 

(2)、frameworks/base/core/jni/AndroidRuntime.cpp中的 :

property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4,"16m"); 

因此解决办法就是将以上2点中默认的16M改大一点,譬如32M。

2)、修改配置文件,适用于烧机后的版本:

修改或添加/system/build.prop中的配置项:

dalvik.vm.heapstartsize=16m
dalvik.vm.heapgrowthlimit=64m
dalvik.vm.heapsize=64m


3)、另外一种做法:在frameworks/base/build/tablet-dalvik-heap.mk中

PRODUCT_PROPERTY_OVERRIDES += \
    dalvik.vm.heapstartsize=5m \
    dalvik.vm.heapgrowthlimit=48m \
    dalvik.vm.heapsize=256m

在device_base.mk中加入:

include frameworks/base/build/tablet-dalvik-heap.mk

在编译的时候会把该信息写到/system/build.prop中。


4、另外还有一种情况是:明明还有很多内存,但是发生OOM了。
这种情况经常出现在生成Bitmap的时候。有兴趣的可以试一下,在一个函数里生成一个13m 的int数组。
再该函数结束后,按理说这个int数组应该已经被释放了,或者说可以释放,这个13M的空间应该可以空出来,
这个时候如果你继续生成一个10M的int数组是没有问题的,反而生成一个4M的Bitmap就会跳出OOM。这个就奇怪了,为什么10M的int够空间,反而4M的Bitmap不够呢?
这个问题困扰很久,在网上,国外各大论坛搜索了很久,一般关于OOM的解释和解决方法都是,如何让GC尽快回收的代码风格之类,并没有实际的支出上述情况的根源。
直到昨天在一个老外的blog上终于看到了这方面的解释,我理解后归纳如下:
在Android中:

1)、一个进程的内存可以由2个部分组成:java 使用内存 ,C 使用内存 ,这两个内存的和必须小于16M,不然就会出现大家熟悉的OOM,这个就是第一种OOM的情况。

2)、更加奇怪的是这个:一旦内存分配给Java后,以后这块内存即使释放后,也只能给Java的使用,这个估计跟java虚拟机里把内存分成好几块进行缓存的原因有关,反正C就别想用到这块的内存了,所以如果Java突然占用了一个大块内存,即使很快释放了:
C能使用的内存 = 16M - Java某一瞬间占用的最大内存。
而Bitmap的生成是通过malloc进行内存分配的,占用的是C的内存,这个也就说明了,上述的4MBitmap无法生成的原因,因为在13M被Java用过后,剩下C能用的只有3M了。

5、在Android平台下实现OpenGL ES程序的贴图加载操作一般是通过BitmapFactory.decodeResource这个api,然后用系统封装好的 GLUtils.texImage2D函数直接转换为gl贴图即可,方便快捷。但在较新版的Android系统中res中的图片文件夹根据dpi设备分辨率的不同,细分了很多文件夹处理以支持不同设备的分辨率加载对应的图片,如drawable-hdpi,drawable-ldpi,drawable- mdpi等,如果没有注意这个问题而将贴图图片随意安置的话,在decode的时候系统会默认根据设备dpi的不同对目标图片格式解码的同时进行大小调整,也就是说有可能破坏原本已经是2^n大小的贴图图片,导致原本在模拟器上正确的绘图在真机上变成大白板!解决这个问题的方法可以将图片放到不受dpi影响的drawable-nodpi中,或者设置BitmapFactory的选项,不处理dpi相关问题。 

6、查询内存限制大小:

ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.getMemoryClass();

以上方法会返回以 M 为单位的数字,可能在不同的平台或者设备上值都不太一样,比如:HTC G7 默认 24M,Galaxy 36M,emulator-2.3 24M,等等。

7、关于这个问题的一些网上资料:
http://blog.csdn.net/wangqilin8888/article/details/7737278
http://blog.csdn.net/wangqilin8888/article/details/7752491
http://my.oschina.net/kangchunhui/blog/67613
http://7dot9.com/2010/08/android-bitmap%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6/
http://blog.csdn.net/wbw1985/article/details/6044724
http://www.cnblogs.com/idiottiger/archive/2012/05/08/2428875.html