android 加载图片oom若干方案小结
本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结。
众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定)。一般我们可以通过获取当前线程的可运行内存来判断,比如系统分给当前运行内存只有16M,而你的图片就有16M,这肯定会oom的。
相关知识介绍
1.颜色模型
常见的颜色模型有RGB、YUV、CMYK等,在大多数图像API中采用的都是RGB模型,Android也是如此;另外,在Android中还有包含透明度Alpha的颜色模型,即ARGB。
2.计算机中颜色值的数字化编码
(1)浮点数编码:比如float: (1.0, 0.5, 0.75),每个颜色分量各占1个float字段,其中1.0表示该分量的值为全红或全绿或全蓝;
(2)24位的整数编码:比如24-bit:(255, 128, 196),每个颜色分量各占8位,取值范围0-255,其中255表示该分量的值为全红或全绿或全蓝;
(3)16位的整数编码:比如16-bit:(31, 45, 31),第1和第3个颜色分量各占5位,取值范围0-31,第2个颜色分量占6位,取值范围0-63;
3.Bitmap在内存中的存储区域
http://www.7dot9.com/2010/08/android-bitmap%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6/一文中对Android内存限制问题做了一些探讨,作者认为Bitmap对象通过栈上的引用来指向堆上的Bitmap对象,而Bitmap对象又对应了一个使用了外部存储的native图像,实际上使用的是byte[]来存储的内存空间。但为了确保外部分配内存成功,应该保证当前已分配的内存加上当前需要分配的内存值,大小不能超过当前堆的最大内存值,而且内存管理上将外部内存完全当成了当前堆的一部分。
4.Java对象的引用类型
(1)强引用(StrongReference)如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
(2)软引用(SoftReference)如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
(3)弱引用(WeakReference)弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
(4)虚引用(PhantomReference)“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
有了上面的基础储备,我们来谈谈图片的oom解决方案:
(1)缓存图像到内存,采用软引用缓存到内存,而不是在每次使用的时候都从新加载到内存;
(2)调整图像大小,手机屏幕尺寸有限,分配给图像的显示区域本身就更小,有时图像大小可以做适当调整;
(3)采用低内存占用量的编码方式,比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省内存;
(4)及时回收图像,如果引用了大量Bitmap对象,而应用又不需要同时显示所有图片,可以将暂时用不到的Bitmap对象及时回收掉;
(5)自定义堆内存分配大小,优化Dalvik虚拟机的堆内存分配;(这里可以参照一些第三方的图片缓存框架)
场景演示
为了说明出现OOM的场景和解决OOM的方法,我们选取了两款不同的机型来做比较:
(1)该应用展示一个gallery,该gallery只加载图片,gallery的adapter中传入图片的路径而不是图片对象本身,adapter动态加载图片;
(2)演示所用的图片预存储到sdcard的cache目录下,文件名分别为a.jpg,b.jpg…r.jpg,总共18张;
(3)图片为规格1920*1200的jpg图片,文件大小在423KB-1.48MB范围内;
(4)运行环境:模拟器——android2.2版本系统——480*320屏幕尺寸;Moto Defy——2.3.4版本CM7系统——854*480屏幕尺寸;
1.演示一
首先采用最简单的图片加载方式,不带任何图片缓存、调整大小或者回收,SimpleImageLoader.class便是承担此职责。加载图片部分的代码如下:
@Override
public Bitmap loadBitmapImage(String path) {
return BitmapFactory.decodeFile(path);
}
@Override
public Drawable loadDrawableImage(String path) {
return new BitmapDrawable(path);
}
演示结果:在模拟器上图片只能加载1-3张,之后便会出现OOM错误;在Defy上不会出现错误;原因是两者内存限制不同,Defy上运行的是第三方ROM,内存分配有40MB。另外gallery每次显示一张图片时,都要重新解析获得一张图片,尽管在Defy上还未曾出错,但当图片量加大,GC回收不及时时,还是有可能出现OOM。
2.演示二
为图片加载的添加一个软引用缓存,每次图片从缓存中获取图片对象,若缓存中不存在,才会从Sdcard加载图片,并将该对象加入缓存。同时软引用的对象也有助于GC在内存不足的时候回收它们。常见的Discache就是这个原理,大家有兴趣的可以自行研究。关键代码
private HashMap> mImageCache;
@Override
public Bitmap loadBitmapImage(String path) {
if(mImageCache.containsKey(path)) {
SoftReferencesoftReference = mImageCache.get(path);
Bitmap bitmap = softReference.get();
if(null != bitmap)
return bitmap;
}
Bitmap bitmap = BitmapFactory.decodeFile(path);
mImageCache.put(path, new SoftReference(bitmap));
return bitmap;
}
@Override
public Drawable loadDrawableImage(String path) {
return new BitmapDrawable(loadBitmapImage(path));
}
3.演示三
为了进一步避免OOM,除了缓存,还可以对图片进行压缩,进一步节省内存,多数情况下调整图片大小并不会影响应用的表现力。这个也是我之前必定做的,就是对图片进行压缩。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//如果该 值设为true那么将不返回实际的bitmap,也不给其分配内存空间,这样就避免内存溢出.
BitmapFactory.decodeFile(path, options);
可以对图片按尺寸压缩,也是不错的方案:
options.inSampleSize = Util.computeSampleSize(options, 600, (int) (1 * 1024 * 1024));
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
4.演示四
在有些情况下,严重缩小图片还是会影响应用的显示效果的,所以有必要在尽可能少地缩小图片的前提下展示图片,手动去回收图片就变得尤为重要。所以这也是一些第三方图片库管理的时候必定用到lrucache算法的原因。
blog.csdn.net/guolin_blog/article/details/34093441
_blog/article/details/34093441
android 加载图片oom若干方案小结的更多相关文章
- Android加载图片OOM错误解决方式
前几天做项目的时候,甲方要求是PAD (SAMSUNG P600 10.1寸 2560*1600)的PAD上显示高分辨率的大图片. SQLITE採用BOLD方式存储图片,这个存取过程就不说了哈,网上一 ...
- Android之批量加载图片OOM问题解决方案
一.OOM问题出现的场景和原因 一个好的app总少不了精美的图片,所以Android开发中图片的加载总是避免不了的,而在加载图片过程中,如果处理不当则会出现OOM的问题.那么如何彻底解决这个问题呢?本 ...
- 图片--Android加载图片导致内存溢出(Out of Memory异常)
Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...
- Android加载图片导致内存溢出(Out of Memory异常)
Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...
- android 加载图片防止内存溢出
图片资源: private int fore[]; private int back[]; fore = new int[]{R.drawable.a0, R.drawable.a1, R.drawa ...
- Android加载图片的策略
实现图片缓存也不难,需要有相应的cache策略.这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且 ...
- android 加载图片框架--Glide使用详解
一.简介 Glide,一个被google所推荐的图片加载库,作者是bumptech.这个库被广泛运用在google的开源项目中,包括2014年的google I/O大会上发布的官方app.(PS:众所 ...
- Android加载图片小结
应用中用到图片加载需要解决的问题 无网络环境下图片不可用 图片的本地缓存,或者默认预加载的图片 低配置机型,加载图像资源超内存(OutOfMemory, OoM) 需要合理使用内存,尤其是bitmap ...
- 解决android加载图片时内存溢出问题
尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过jav ...
随机推荐
- Conference-Web Search and Data Mining
Conference WSDM(Web Search and Data Mining)The ACM WSDM Conference Series 不像KDD.WWW或者SIGIR,WSDM因为从最开 ...
- Bootstrap3 表单-输出内联表单
为 <form> 元素添加 .form-inline 类可使其内容左对齐并且表现为 inline-block 级别的控件.只适用于视口(viewport)至少在 768px 宽度时(视口宽 ...
- Vue 踩坑记
参考: https://forum.vuejs.org/t/unknown-issues-in-change-event-of-radio-in-vue-2-x-webpack-2-x/11034 v ...
- Bootstrap3 排版-对齐
通过文本对齐类,可以简单方便的将文字重新对齐. Left aligned text. Center aligned text. Right aligned text. Justified text. ...
- 20160215.CCPP体系详解(0025天)
程序片段(01):01.Malloc.c 内容概要:Malloc拓展 #include <stdio.h> #include <stdlib.h> //01.内存伸缩函数: / ...
- Dynamics CRM2016 关于修改部署管理员账号权限引发的问题
最近在用2016做项目,一个同事的一个操作给我带来了一个头疼的问题,他把部署管理员的CRM账号的管理员权限给移除了,导致整个系统的所有账号进CRM都是下图这样 即使系统中还存在其他的拥有管理员权限的账 ...
- intel-hadoop/HiBench流程分析----以贝叶斯算法为例
1.HiBench算法简介 Hibench 包含9个典型的hadoop负载(micro benchmarks,hdfs benchmarks,web search bench marks,machin ...
- Android 结合实际项目学会ListView局部刷新和相关知识《一》
转载本专栏博客,请注明出处:道龙的博客 最近在公司参与的项目中有一个界面需要做局部UI更新处理,把其化烦为简为Demoi形式写在这里.我们还是运行该Demo,知道ListView局部刷新的使用场景:( ...
- RxJava(十一)defer操作符实现代码支持链式调用
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52597643 本文出自:[余志强的博客] 一.前言 现在越来越多An ...
- UNIX网络编程——Socket通信原理和实践
我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠so ...