Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory  Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证):
 方案一、读取图片时注意方法的调用,适当压缩  尽量不要使用setImageBitmapsetImageResourceBitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。 因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的  source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。

InputStream is = this.getResources().openRawResource(R.drawable.pic1);

BitmapFactory.Options options = new  BitmapFactory.Options();

options.inJustDecodeBounds =  false;

options.inSampleSize =  10;   // width,hight设为原来的十分一

Bitmap btp =  BitmapFactory.decodeStream(is, null,  options);

如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。

/**

*  以最省内存的方式读取本地资源的图片

*  @param context

*  @param resId

*  @return

*/

public  static  Bitmap readBitMap(Context  context, int resId){

BitmapFactory.Options opt = new  BitmapFactory.Options();

opt.inPreferredConfig =  Bitmap.Config.RGB_565;

opt.inPurgeable = true;

opt.inInputShareable = true;

//  获取资源图片

InputStream is =  context.getResources().openRawResource(resId);

return  BitmapFactory.decodeStream(is, null, opt);

}

另外,decodeStream直接拿图片来读取字节码,
 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,
 否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
方案二、在适当的时候及时回收图片占用的内存  通常Activity或者Fragment在onStop/onDestroy时候就可以释放图片资源:

if(imageView !=  null &&  imageView.getDrawable() != null){

Bitmap oldBitmap =  ((BitmapDrawable) imageView.getDrawable()).getBitmap();

imageView.setImageDrawable(null);

if(oldBitmap !=  null){

oldBitmap.recycle();

oldBitmap =  null;

}

}

//  Other code.

System.gc();

在释放资源时,需要注意释放的Bitmap或者相关的Drawable是否有被其它类引用。如果正常的调用,可以通过Bitmap.isRecycled()方法来判断是否有被标记回收;而如果是被UI线程的界面相关代码使用,就需要特别小心避免回收有可能被使用的资源,不然有可能抛出系统异常:
E/AndroidRuntime: java.lang.IllegalArgumentException: Cannot draw
recycled  bitmaps 并且该异常无法有效捕捉并处理。
方案三、不必要的时候避免图片的完整加载 只需要知道图片大小的情形下,可以不完整加载图片到内存。 在使用BitmapFactory压缩图片的时候,BitmapFactory.Options设置inJustDecodeBounds为true后,再使用decodeFile()等方法,可以在不分配空间状态下计算出图片的大小。示例:

BitmapFactory.Options opts =  new  BitmapFactory.Options();

//  设置inJustDecodeBounds为false

opts.inJustDecodeBounds = false;

//  使用decodeFile方法得到图片的宽和高

BitmapFactory.decodeFile(path,  opts);

//  打印出图片的宽和高

Log.d("example", opts.outWidth + "," + opts.outHeight);

(ps:原理其实就是通过图片的头部信息读取图片的基本信息)
方案四、优化Dalvik虚拟机的堆内存分配  堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。 Heap  Utilization是堆的利用率。当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。使用  dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。

private final static float  TARGET_HEAP_UTILIZATION = 0.75f;

//  在程序onCreate时就可以调用

VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

方案五、自定义堆(Heap)内存大小  对于一些Android项目,影响性能瓶颈的主要是Android自己内存管理机制问题,目前手机厂商对RAM都比较吝啬,对于软件的流畅性来说RAM对性能的影响十分敏感,除了优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的
 dalvik.system.VMRuntime类来设置最小堆内存为例:

private final static int  CWJ_HEAP_SIZE = 6 * 1024 * 1024  ;

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);  //  设置最小heap内存为6MB大小。

但是上面方法还是存在问题,函数setMinimumHeapSize其实只是改变了堆的下限值,它可以防止过于频繁的堆内存分配,当设置最小堆内存大小超过上限值(Max Heap  Size)时仍然采用堆的上限值,对于内存不足没什么作用。  
在默认情况下android进程的内存占用量为16M,因为Bitmap他除了java中持有数据外,底层C++的  skia图形库还会持有一个SKBitmap对象,因此一般图片占用内存推荐大小应该不超过8M。这个可以调整,编译源代码时可以设置参数。

参考资料:http://www.tuicool.com/articles/yemM7zf

方案六:在Manifest.xml文件里面的<application  里面添加Android:largeHeap="true"

简单粗暴。这种方法允许应用需要耗费手机很多的内存空间,但却是最快捷的解决办法

Android加载图片导致内存溢出(Out of Memory异常)的更多相关文章

  1. 图片--Android加载图片导致内存溢出(Out of Memory异常)

    Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory  Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...

  2. WPF循环加载图片导致内存溢出的解决办法

    程序场景:一系列的图片,从第一张到最后一张依次加载图片,形成“动画”. 生成BitmapImage的方法有多种: 1. var source=new BitmapImage(new Uri(" ...

  3. android 加载图片防止内存溢出

    图片资源: private int fore[]; private int back[]; fore = new int[]{R.drawable.a0, R.drawable.a1, R.drawa ...

  4. 解决android加载图片时内存溢出问题

    尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过jav ...

  5. Android加载大图到内存如何避免内存溢出?

    加载大图怎么避免溢出实际做法就是对图像进行压缩,也是比较老的话题了,在最初做android时是经常会遇到的问题,而如今对于图片加载这一块都已经有很成熟稳定的三方库来弄它了,所以图片加载过大内存溢出的比 ...

  6. [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html  这个可以实现ImageView异步加载 ...

  7. BitmapFactory 加载图片到内存

    Bitmap占用内存分析 Android的虚拟机是基于寄存器的Dalvik,它的最大堆(单个进程可用内存)大小一般是16M,当然不同设备是不一样的,可以查看/system/build.prop文件,[ ...

  8. android 加载图片oom若干方案小结

    本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结. 众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定).一般我们可以通过获取当 ...

  9. Android加载图片OOM错误解决方式

    前几天做项目的时候,甲方要求是PAD (SAMSUNG P600 10.1寸 2560*1600)的PAD上显示高分辨率的大图片. SQLITE採用BOLD方式存储图片,这个存取过程就不说了哈,网上一 ...

随机推荐

  1. PHP版本 D-Link 动态域名客户端

    <?php /* * D-Link 动态域名客户端.主域名www.dlinkddns.com 和 www.dlinkddns.com.cn * 首先获取外网IP,若IP没有变化,则结束运行:否则 ...

  2. ADO.net简单增删改查

    嘿嘿,又到了总结了的时间,今天我们学习了ADO.net,什么是ADO.NET:ADO.NET就是一组类库,这组类库可以让我们通过程序的方式访问数据库,就像System.IO下的类操作文件一样, Sys ...

  3. Java基础学习总结(40)——Java程序员最常用的8个Java日志框架

    作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...

  4. SimpleDateFormat的使用问题

    今天对过去的代码进行重构,因为使用静态方法调用的原因,使用了一个静态的SimpleDateFormat,结果FindBug报错了,查看了一下,说是使用了静态的SimpleDateFormat对象. S ...

  5. 【Codeforces Round #432 (Div. 1) B】Arpa and a list of numbers

    [链接]h在这里写链接 [题意] 定义bad list是一个非空的.最大公约数为1的序列.给定一个序列,有两种操作:花费x将一个元素删除.花费y将一个元素加1,问你将这个序列变为good list所需 ...

  6. SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能

    SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能. 第一步:配置web.xml <!-- 配置Shiro过滤器,先让Shiro ...

  7. [React Intl] Render Content with Placeholders using react-intl FormattedMessage

    Learn how to use react-intl to set dynamic values into your language messages. We’ll also learn how ...

  8. 【UVA】434-Matty&#39;s Blocks

    一道非常easy想复杂的题,给出主视图和右视图,计算最少能用几个正方体组成相应的视图,以及最多还能加几块正方体. 求最多加入事实上就是求出最多的正方体数减去最少的,主要就是最少的不好求. 一開始各种模 ...

  9. 全双工 串口 stm32

  10. 7.2 基础知识ArrayMap

    1.android源码中维护有键值对,通过键可以找到值 Java中Object是所有类的父类,对于键值对的保存如果使用个ObjectArray数组,比如N个位置存放键,N+1的位置就存放值,那么如果键 ...