我遇到过加载图片时内存溢出的情况。其原因我认为是图片存储的大小与显示时占用空间大小的冲突。图片在存储时经常是以压缩格式存储,例如jpg,png等,但在真正显示到界面元素时,将会还原成位图bmp来显示,所以在读取过程中会出现溢出,一个jpg变成bmp依据其压缩比可能膨胀几十倍,每个引用的堆空间是有限的,突然加载一个几兆的图片直接就爆了。所以读取图片时,如果是本地图片,那么可以先通过读取头信息来确定图片大小,决定是否需要压缩分辨率,或者色彩。而若是网络资源图片,那么需要先将图片拉取回来,再做类似处理。至于说在本地建立回收机制以及本地实现图片资源重复利用,使用软引用等方法,这些是提高效率的手段,却非根本。因为很有可能一张分辨率巨大的纯色图片(这种图片jpg可能只有几kb,但bmp可能十几兆)在显示时就直接崩掉程序。当然我是半路出家,可能我的看法并不正确,希望大家指正。

解决方案 »

  1.   

    解决过一些OOM的问题
    一般来说图片的OOM都是出现在java heap的里面
    由于图片资源较大 而android的上层接口封装 比如imageview等里面并在申请内存前并没有对图片进行压缩
    以及在listview或者table加载图片的时候是大量图片一起加载 一个页面会有多个图片的时候 很容易出现这种OOM
    之前试过有两种改法可行
    1.自己实现一套专门显示图片的view类,直接继承自view,在显示的时候通过asset类获取图片的时候,手动查找缩略图或者通过bitmapfactory进行处理,或者通过底层ndk接口使用native层内存
    2.针对界面做一个假的图片,比如一个九宫格式的图片界面,可以使用一整个image,但是填充的时候预先把图片缩小之后填到各自对应的位子,即整个界面是一个image,而构造这个image的过程由自己实现,对按键触发,通过吃touch的位置来判断。仅供参考
    另外有很多开源的库 貌似也在尝试其他思路解决OOM问题
      

  2.   

    分配heap堆这是非常好的一个方法,有没有考虑缓存了
      

  3.   

    oom的出现有多种原因,常见的主要是撑爆,之前说的图片读取主要是这点,还有可能是引用了失效的内存。
    有关撑爆了的情况,要解决,无外乎开源节流。而每个应用被系统分配的空间是有最大限制的,所以开源基本就不想了。主要还是在节流上。就我平时所使用的大约几个方面
    1,就是压缩资源,刚才说了,就读取图片来说,我认为压缩(调整分辨率,色彩等)是根本。
    2,软引用,一般的强引用会导致未显式释放就无法回收的问题,使用软引用系统可以在有需要时自动处理。
    3,手动回收,像bmp这种占用空间过大,有不一定能时刻显示,完全可以在切换到后台时recycle并设置为null,如果是过后还需要使用的网络图片资源可以转换为本地文件存储,通过建立内存中资源名称与本地存储的映射来实时读取。
    4,实时关闭需要长期占用的资源,例如 Cursor,file等,随时使用随时关闭。
    5,避免在static 中保存大数据。
    6,实现一些控件的重复利用,例如listview或者gridview中因滑动不显示部分的view完全可以重复利用。
    7,对线程中临界资源绝对要管理好,否则很容易因各种莫名其妙的原因导致内存无法释放,或者无法引用。
    8,其他种种。另外还有个引用不存在资源一般是因为在系统中注册了某个通知到本应用的某个处理类,结果忘了注销,最后系统调用时就悲剧了。
      

  4.   


    分配heap堆这是非常好的一个方法,有没有考虑缓存了我觉得这个问题可以从几个方向去看
    1.作为一个应用开发者,(仅能修改apk的代码和逻辑)
    2.作为一个系统开发者,(深度定制android系统的角度)
    3.作为项目的其他角色    (美工优化图片?编译配置管理员修改app heap大小?...)怎么去解决这个OOM问题
      

  5.   

    面试时这个还真的是必问的。
    以前有修改定制过imageloader的源码,那时对这块还是很熟悉的,现在还真不好说了。
    里面提供了很多缓存机制,软引用、Lrucache等;再限制缓存的大小;对图片的压缩;对view的复用
      

  6.   

    第一次逛android论坛。。多多关照
    我就从实际开发的角度来谈谈避免加载图片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(); //催促垃圾回收器尽快回收,但并不会真正调用回收。
    下午有空可以讲下我学到的高效加载图片的流程。
      

  7.   

    夜店大神,你觉得解决OOM有效方法有哪些?
      

  8.   

    解决这种方法首先要理解系统内存的分配机制,做到有申请内存有释放,谁申请谁来释放;做Java研发的兄弟可能都忽略了这一点;把所有内存回收交给了垃圾回收器。可实际上你手动申请内存没有相应的释构方法释放对象,垃圾加收器是没办法回收的