MyException - 我的异常网
当前位置:我的异常网» Android » Android4.0 输出分辨率改成1280*720后,出现Out of

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

www.myexceptions.net  网友分享于:2015-08-26  浏览:95次
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




文章评论

十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员都该阅读的书
程序员都该阅读的书
每天工作4小时的程序员
每天工作4小时的程序员
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
漫画:程序员的工作
漫画:程序员的工作
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
Java程序员必看电影
Java程序员必看电影
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
一个程序员的时间管理
一个程序员的时间管理
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
如何成为一名黑客
如何成为一名黑客
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
那些争议最大的编程观点
那些争议最大的编程观点
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
程序员和编码员之间的区别
程序员和编码员之间的区别
编程语言是女人
编程语言是女人
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
我是如何打败拖延症的
我是如何打败拖延症的
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
我的丈夫是个程序员
我的丈夫是个程序员
代码女神横空出世
代码女神横空出世
 程序员的样子
程序员的样子
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
旅行,写作,编程
旅行,写作,编程
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
鲜为人知的编程真相
鲜为人知的编程真相
10个调试和排错的小建议
10个调试和排错的小建议
程序员必看的十大电影
程序员必看的十大电影
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有