我遇到过加载图片时内存溢出的情况。其原因我认为是图片存储的大小与显示时占用空间大小的冲突。图片在存储时经常是以压缩格式存储,例如jpg,png等,但在真正显示到界面元素时,将会还原成位图bmp来显示,所以在读取过程中会出现溢出,一个jpg变成bmp依据其压缩比可能膨胀几十倍,每个引用的堆空间是有限的,突然加载一个几兆的图片直接就爆了。所以读取图片时,如果是本地图片,那么可以先通过读取头信息来确定图片大小,决定是否需要压缩分辨率,或者色彩。而若是网络资源图片,那么需要先将图片拉取回来,再做类似处理。至于说在本地建立回收机制以及本地实现图片资源重复利用,使用软引用等方法,这些是提高效率的手段,却非根本。因为很有可能一张分辨率巨大的纯色图片(这种图片jpg可能只有几kb,但bmp可能十几兆)在显示时就直接崩掉程序。当然我是半路出家,可能我的看法并不正确,希望大家指正。
解决方案 »
- android xmpp推送,与系统版本的问题
- 帮解决问题:android下的office读取、显示方案
- Parent directory of file is not writable
- android receiver监听解锁问题
- 请问大家,如何用代码修改一个android应用程序在桌面的图标呢
- 系统的拔号程序能够屏蔽HOME按键,求解释
- 联系信息相关类,2.1中被废除,有什么好办法让1.5和2.1的兼容呢?
- 关于安卓软件开发的问题
- 【新手请教】安卓K歌评分一类的软件开发
- 有谁用过Android-Pdf-Viewer-Library这个开源框架
- 为什么我的SOCKET输出要暂停一下才能收到?
- 请问关于微信上 滑动屏幕上 的控件会改变显示的问题
一般来说图片的OOM都是出现在java heap的里面
由于图片资源较大 而android的上层接口封装 比如imageview等里面并在申请内存前并没有对图片进行压缩
以及在listview或者table加载图片的时候是大量图片一起加载 一个页面会有多个图片的时候 很容易出现这种OOM
之前试过有两种改法可行
1.自己实现一套专门显示图片的view类,直接继承自view,在显示的时候通过asset类获取图片的时候,手动查找缩略图或者通过bitmapfactory进行处理,或者通过底层ndk接口使用native层内存
2.针对界面做一个假的图片,比如一个九宫格式的图片界面,可以使用一整个image,但是填充的时候预先把图片缩小之后填到各自对应的位子,即整个界面是一个image,而构造这个image的过程由自己实现,对按键触发,通过吃touch的位置来判断。仅供参考
另外有很多开源的库 貌似也在尝试其他思路解决OOM问题
有关撑爆了的情况,要解决,无外乎开源节流。而每个应用被系统分配的空间是有最大限制的,所以开源基本就不想了。主要还是在节流上。就我平时所使用的大约几个方面
1,就是压缩资源,刚才说了,就读取图片来说,我认为压缩(调整分辨率,色彩等)是根本。
2,软引用,一般的强引用会导致未显式释放就无法回收的问题,使用软引用系统可以在有需要时自动处理。
3,手动回收,像bmp这种占用空间过大,有不一定能时刻显示,完全可以在切换到后台时recycle并设置为null,如果是过后还需要使用的网络图片资源可以转换为本地文件存储,通过建立内存中资源名称与本地存储的映射来实时读取。
4,实时关闭需要长期占用的资源,例如 Cursor,file等,随时使用随时关闭。
5,避免在static 中保存大数据。
6,实现一些控件的重复利用,例如listview或者gridview中因滑动不显示部分的view完全可以重复利用。
7,对线程中临界资源绝对要管理好,否则很容易因各种莫名其妙的原因导致内存无法释放,或者无法引用。
8,其他种种。另外还有个引用不存在资源一般是因为在系统中注册了某个通知到本应用的某个处理类,结果忘了注销,最后系统调用时就悲剧了。
分配heap堆这是非常好的一个方法,有没有考虑缓存了我觉得这个问题可以从几个方向去看
1.作为一个应用开发者,(仅能修改apk的代码和逻辑)
2.作为一个系统开发者,(深度定制android系统的角度)
3.作为项目的其他角色 (美工优化图片?编译配置管理员修改app heap大小?...)怎么去解决这个OOM问题
以前有修改定制过imageloader的源码,那时对这块还是很熟悉的,现在还真不好说了。
里面提供了很多缓存机制,软引用、Lrucache等;再限制缓存的大小;对图片的压缩;对view的复用
我就从实际开发的角度来谈谈避免加载图片oom的情况:
(1)首先最简单的就是尽量让美工在保证图片质量的情况下尽量提供小的图片
(2)在使用图片时也要根据实际情况,如果只是在100*100的view里面加载800*480的图片,肯定是不合适的。这时候就要用BitmapFactory来压缩图片,包括大小压缩和颜色质量压缩(inSimapleSize,Bitmap.Config.RGB_565)
//ARGB_8888 每个像素占用(8+8+8+8)/4 = 4字节
//RGB_565 每个像素占用(5+6+5)/4 = 2字节
(3)在用BitmapFactory生成图片时,尽量使用BitmapFactory.decodeStream方法。原因在于其直接调用JNI层的nativeDecodeAsset()来完成decode,无需在使用java层的createBitmap()生成临时bitmap,节约了内存。
(4)bitmap在确定不需要再次使用后请及时回收对象,
回收三部曲:
1.bitmap.recyle(); //解除bitmap引用与native位图的关系,并不会真正回收位图,只是告诉
2.bitmap = null; //将bitmap引用置空
3.System.gc(); //催促垃圾回收器尽快回收,但并不会真正调用回收。
下午有空可以讲下我学到的高效加载图片的流程。