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 ...
随机推荐
- Bootstrap3 表单-基本表单
单独的表单控件会被自动赋予一些全局样式.所有设置了 .form-control 类的 <input>.<textarea> 和 <select> 元素都将被默认设置 ...
- makefile 和shell文件相互调用
shell 文件内调用makefile文件: #!/bin/bash cd ctemplate-2.1./configuresudo make -f installcd ../cd Templat ...
- iOS开源加密相册Agony的实现(一)
简介 虽然目前市面上有一些不错的加密相册App,但不是内置广告,就是对上传的张数有所限制.本文介绍了一个加密相册的制作过程,该加密相册将包括多密码(输入不同的密码即可访问不同的空间,可掩人耳目).Wi ...
- iOS 应用提交到iTunes Connect,显示"正在处理"后消失不见
打包上传iTunes Connect 成功后,进入iTunes Connect 会看到如下的构建信息: 可是,过一会再刷新该页面,构建的版本就消失了. 出现如上所述的情况,主要目前已知的有两种原因: ...
- 通过JNDI从服务器容器中获取资源_Spring JNDI+Mysql+Tomcat
通过JNDI从服务器容器中获取DataSource资源 (由容器管理,不要关闭它,容器自己会处理)上一篇我们使用的是dbcp,这里使用JNDI: 使用JNDI连接数据: 在Spring可以注释 < ...
- SELinux策略语言--客体类别和许可
1. 简介 SELinux策略语言主要描述policy.conf的相关语法,其相关部分如下图所示: 2. 客体类别 定义内核支持的客体类别和许可的策略语言指令,并对SELinux系统中内核客体类别标准 ...
- Team Foundation Server 2015 Update 2.1 发布日志
微软在 2016年5月5日发布了Visual Studio Team Foundation Server 2015 update 2.1. 下面我们来看看Update2.1中给我们带来了哪些新功能. ...
- 自定义AlertDialog(仿微信)
安卓自定义AlertDialog,原理很简单: AlertDialog dialog = new AlertDialog.Builder(MainActivity.this).create(); di ...
- MySQl数据库必会sql语句加强版
这篇承接上一篇<mysql必会sql语句>:http://blog.csdn.net/qq_32059827/article/details/51763950 这一篇属于加强版,问题和sq ...
- numpy教程:快速傅里叶变换模块numpy.fft
http://blog.csdn.net/pipisorry/article/details/51050297 快速傅里叶变换 NumPy中,fft模块提供了快速傅里叶变换的功能.在这个模块中,许多函 ...