当前位置: 首页 > news >正文

Bitmap引起的OOM问题

作者:向阳逐梦

1.什么是OOM?为什么会引起OOM?

答:Out Of Memory(内存溢出),我们都知道Android系统会为每个APP分配一个独立的工作空间,或者说分配一个单独的Dalvik虚拟机,这样每个APP都可以独立运行而不相互影响!而Android对于每个Dalvik虚拟机都会有一个最大内存限制,如果当前占用的内存加上我们申请的内存资源超过了这个限制,系统就会抛出OOM错误!另外,这里别和RAM混淆了,即时当前RAM中剩余的内存有1G多,但是OOM还是会发生!别把RAM(物理内存)和OOM扯到一起!另外RAM不足的话,就是杀应用了,而不是仅仅是OOM了!而这个Dalvik中的最大内存标准,不同的机型是不一样的,可以调用:

ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
Log.e("HEHE","最大内存:" + activityManager.getMemoryClass());

获得正常的最大内存标准,又或者直接在命令行键入:

adb shell getprop | grep dalvik.vm.heapgrowthlimit

你也可以打开系统源码/system/build.prop文件,看下文件中这一部分的信息得出:

dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=192m
dalvik.vm.heapsize=512m
dalvik.vm.heaptargetutilization=0.75
dalvik.vm.heapminfree=2m
dalvik.vm.heapmaxfree=8m

我们关注的地方有三个:heapstartsize堆内存的初始大小,heapgrowthlimit标准的应用的最大堆内存大小,heapsize则是设置了使用android:largeHeap的应用的最大堆内存大小!

我这里试了下手头几个机型的正常最大内存分配标准:

你也可以试试自己手头的机子~

好啦,不扯了,关于OOM问题的产生,就扯到这里,再扯就到内存管理那一块了,可是个大块头,现在还啃不动…下面我们来看下避免Bitmap OOM的一些技巧吧!

2.避免Bitmap引起的OOM技巧小结

1)采用低内存占用量的编码方式

上一节说了BitmapFactory.Options这个类,我们可以设置下其中的inPreferredConfig属性,默认是Bitmap.Config.ARGB_8888,我们可以修改成Bitmap.Config.ARGB_4444Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位Bitmap.Config ARGB_8888:每个像素占八位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位默认使用ARGB_8888,即一个像素占4个字节!

2)图片压缩

同样是BitmapFactory.Options,我们通过inSampleSize设置缩放倍数,比如写2,即长宽变为原来的1/2,图片就是原来的1/4,如果不进行缩放的话设置为1即可!但是不能一味的压缩,毕竟这个值太小的话,图片会很模糊,而且要避免图片的拉伸变形,所以需要我们在程序中动态的计算,这个inSampleSize的合适值,而Options中又有这样一个方法:inJustDecodeBounds,将该参数设置为true后,decodeFiel并不会分配内存空间,但是可以计算出原始图片的长宽,调用options.outWidth/outHeight获取出图片的宽高,然后通过一定的算法,即可得到适合的inSampleSize,这里感谢街神提供的代码——摘自鸿洋blog!

public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {int width = options.outWidth;int height = options.outHeight;int inSampleSize = 1;if (width > reqWidth || height > reqHeight) {int widthRadio = Math.round(width * 1.0f / reqWidth);int heightRadio = Math.round(height * 1.0f / reqHeight);inSampleSize = Math.max(widthRadio, heightRadio);}return inSampleSize;
}

然后使用下上述的方法即可:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 设置了此属性一定要记得将值设置为false
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(url, options);
options.inSampleSize = computeSampleSize(options,128,128);
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
/* 下面两个字段需要组合使用 */  
options.inPurgeable = true;
options.inInputShareable = true;
options.inJustDecodeBounds = false;
try {bitmap = BitmapFactory.decodeFile(url, options);
} catch (OutOfMemoryError e) {Log.e(TAG, "OutOfMemoryError");
}

3.及时回收图像

如果引用了大量的Bitmap对象,而应用又不需要同时显示所有图片。可以将暂时不用到的Bitmap对象及时回收掉。对于一些明确知道图片使用情况的场景可以主动recycle回收,比如引导页的图片,使用完就recycle,帧动画,加载一张,画一张,释放一张!使用时加载,不显示时直接置null或recycle!比如:imageView.setImageResource(0); 不过某些情况下会出现特定图片反复加载,释放,再加载等,低效率的事情…

4.其他方法

下面这些方法,我并没有用过,大家可以自行查阅相关资料:

1.简单通过SoftReference引用方式管理图片资源

建个SoftReference的hashmap使用图片时先查询这个hashmap是否有softreference, softreference里的图片是否为空,如果为空就加载图片到softreference并加入hashmap。无需再代码里显式的处理图片的回收与释放,gc会自动处理资源的释放。这种方式处理起来简单实用,能一定程度上避免前一种方法反复加载释放的低效率。但还不够优化。

示例代码:

private Map<String, SoftReference<Bitmap>> imageMap = new HashMap<String, SoftReference<Bitmap>>();public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) {SoftReference<Bitmap> reference = imageMap.get(imageUrl);if(reference != null) {if(reference.get() != null) {return reference.get();}}final Handler handler = new Handler() {public void handleMessage(final android.os.Message msg) {//加入到缓存中Bitmap bitmap = (Bitmap)msg.obj;imageMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));if(imageCallBack != null) {imageCallBack.getBitmap(bitmap);}}};new Thread(){public void run() {Message message = handler.obtainMessage();message.obj = downloadBitmap(imageUrl);handler.sendMessage(message);}}.start();return null ;
}// 从网上下载图片
private Bitmap downloadBitmap (String imageUrl) {Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());return bitmap ;} catch (Exception e) {e.printStackTrace();return null;} 
}
public interface ImageCallBack{void getBitmap(Bitmap bitmap);
}

2.LruCache + sd的缓存方式

Android 3.1版本起,官方还提供了LruCache来进行cache处理,当存储Image的大小大于LruCache 设定的值,那么近期使用次数最少的图片就会被回收掉,系统会自动释放内存!

使用示例

步骤:

1)要先设置缓存图片的内存大小,我这里设置为手机内存的1/8,手机内存的获取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);

2)LruCache里面的键值对分别是URL和对应的图片

3)重写了一个叫做sizeOf的方法,返回的是图片数量。

private LruCache<String, Bitmap> mMemoryCache;
private LruCacheUtils() {if (mMemoryCache == null)mMemoryCache = new LruCache<String, Bitmap>(MAXMEMONRY / 8) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {// 重写此方法来衡量每张图片的大小,默认返回图片数量。return bitmap.getRowBytes() * bitmap.getHeight() / 1024;}@Overrideprotected void entryRemoved(boolean evicted, String key,Bitmap oldValue, Bitmap newValue) {Log.v("tag", "hard cache is full , push to soft cache");}};
}

4)下面的方法分别是清空缓存、添加图片到缓存、从缓存中取得图片、从缓存中移除。

移除和清除缓存是必须要做的事,因为图片缓存处理不当就会报内存溢出,所以一定要引起注意。

public void clearCache() {if (mMemoryCache != null) {if (mMemoryCache.size() > 0) {Log.d("CacheUtils","mMemoryCache.size() " + mMemoryCache.size());mMemoryCache.evictAll();Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size());}mMemoryCache = null;}
}public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (mMemoryCache.get(key) == null) {if (key != null && bitmap != null)mMemoryCache.put(key, bitmap);} elseLog.w(TAG, "the res is aready exits");
}public synchronized Bitmap getBitmapFromMemCache(String key) {Bitmap bm = mMemoryCache.get(key);if (key != null) {return bm;}return null;
}/*** 移除缓存* * @param key*/
public synchronized void removeImageCache(String key) {if (key != null) {if (mMemoryCache != null) {Bitmap bm = mMemoryCache.remove(key);if (bm != null)bm.recycle();}}
}

其实想要全面掌握好 Android 性能优化的话,这些知识点你必须要有所了解,如: 内存优化、网络优化、卡顿优化、存储优化……等,其实除了这些,像Framework 底层原理逻辑话,也需要有一定的了解,为了让大家一次都可以了解全,所以将其整合成名为《Android 性能优化核心知识点手册》和《Android Framework核心知识点手册》,大家可以参考下:

《Android 性能调优核心笔记汇总》:https://qr18.cn/FVlo89

《Android 性能监控框架》:https://qr18.cn/FVlo89

《Android Framework核心知识点手册》:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战

相关文章:

Bitmap引起的OOM问题

作者&#xff1a;向阳逐梦 1.什么是OOM&#xff1f;为什么会引起OOM&#xff1f; 答&#xff1a;Out Of Memory(内存溢出)&#xff0c;我们都知道Android系统会为每个APP分配一个独立的工作空间&#xff0c;或者说分配一个单独的Dalvik虚拟机&#xff0c;这样每个APP都可以独立…...

【JavaEE初阶】认识线程(Thread)

目录 &#x1f33e; 前言 &#x1f33e; 了解线程 &#x1f308;1.1 线程是什么&#xff1f; &#x1f308;1.2 一些基本问题 &#x1f33e;2、创建线程的方式 &#x1f308; 2.1 继承Thread类 &#x1f308; 2.2 实现Runnable接口并重写run()方法 &#x1f308; 注意…...

自动化运维工具一Ansible Roles实战

目录 一、Ansible Roles概述 1.1.roles官方的目录结构 1.2.Ansible Roles依赖关系 二、Ansible Roles案例实战 2.1.Ansible Roles NFS服务 2.2 Roles Memcached 2.3 Roles-rsync服务 一、Ansible Roles概述 之前介绍了 Playbook 的使用方法&#xff0c;对于批量任务的部…...

json 中有递归parentId节点转 c#实体类时如何处理

如果您有一个具有递归parentId节点的JSON数据&#xff0c;并且您需要将其转换为C#实体类&#xff0c;则可以使用以下方法&#xff1a; 创建一个类来表示JSON对象的节点&#xff0c;包括它的属性和子节点。 public class Node {public int Id { get; set; }public string Name …...

给大家介绍几个手机冷门但好用的小技巧

技巧一&#xff1a;拍照识别植物 手机的拍照识别植物功能是指在使用手机相机时&#xff0c;可以通过对植物进行拍照&#xff0c;并通过植物识别技术&#xff0c;获取植物的相关信息和资料。其主要优点如下&#xff1a; 方便实用&#xff1a;使用拍照识别植物功能&#xff0c;…...

2.3 定点乘法运算

学习目标&#xff1a; 如果我要学习定点乘法运算&#xff0c;我会按照以下步骤进行学习&#xff1a; 确定学习目标&#xff1a;明确学习定点乘法运算的目的和重点&#xff0c;以便有针对性地进行学习。 掌握基础知识&#xff1a;首先需要了解定点数和定点乘法的基础知识&…...

C++每日一练:打家劫室(详解动态规划法)

文章目录 前言一、题目二、分析三、代码总结 前言 这题目出得很有意思哈&#xff0c;打劫也是很有技术含量滴&#xff01;不会点算法打劫这么粗暴的工作都干不好。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 题目名称&#xff1a; 打家…...

Wireshark使用

Capture Filters 语法 <Protocol name><Direction><Hosts><Value><Logical operations><Expressions> e.g 1.tcp src port 443 只抓取来源端口是443的tcp数据 2.not arp 不获取arp数据 3.port 80 获取端口是80的数据&#xff0c;不指…...

这才是 SpringBoot 统一登录鉴权、异常处理、数据格式 的正确姿势

本篇将要学习 Spring Boot 统一功能处理模块&#xff0c;这也是 AOP 的实战环节 用户登录权限的校验实现接口 HandlerInterceptor WebMvcConfigurer 异常处理使用注解 RestControllerAdvice ExceptionHandler 数据格式返回使用注解 ControllerAdvice 并且实现接口 Response…...

Java面试题总结 | Java面试题总结6-MYSQL模块(持续更新)

Mysql 文章目录 Mysql关系型数据库和非关系型数据库的区别什么是ORM?-**mybatis**如何评估一个索引创建的是否合理&#xff1f;Count函数执行效果上&#xff1a;执行效率上&#xff1a;count(主键)和count(列名) 数据库的三大范式Mysql中char和varchar的区别数据库设计或者功能…...

Linux命令集(Linux文件管理命令--mv指令篇)

Linux命令集&#xff08;Linux文件管理命令--mv指令篇&#xff09; Linux文件管理命令集&#xff08;mv指令篇&#xff09;2. mv(move)1. 文件移动2. 递归移动目录3. 文件目录重命名4. 强制移动5. 备份覆盖的目标文件6. 试探性移动7. 显示移动进度8. 补集操作9. 修改文件的权限…...

不一样的 Git 之间 | GitLab vs GitHub vs Gitee vs GitCode

Git仓库对比&#xff1a;GitLab vs GitHub vs Gitee vs GitCode 在软件开发中&#xff0c;版本控制是必不可少的工具之一。Git作为目前最为流行的版本控制系统&#xff0c;也逐渐成为了开发者们的标配。但是&#xff0c;如何选择一个合适的Git仓库来存储您的代码呢&#xff1f;…...

海尔牵头IEEE P2786国际标准通过Sponsor投票并连任工作组主席

01 海尔牵头IEEE P2786国际标准 通过Sponsor投票 并连任工作组主席 海尔牵头制定的全球首个服装物联网国际标准IEEE P2786《Standard for General Requirements and Interoperability for Internet of Clothing》通过Sponsor投票&#xff0c;标志着该国际标准草案得到了行业…...

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析 倾斜摄影超大场景的三维模型的顶层合并需要对纹理进行压缩和抽稀处理&#xff0c;以减小数据量和提高数据的传输和展示性能。以下是一种常用的纹理压缩和抽稀处理技术&#xff1a; 1、纹理图集 纹理瓦片化…...

linux命令之iostat详解

iostat 监视系统输入输出设备和CPU的使用情况 推荐Linux命令在线工具&#xff1a;linux在线查询工具 补充说明 iostat命令 被用于监视系统输入输出设备和CPU的使用情况。它的特点是汇报磁盘活动统计情况&#xff0c;同时也会汇报出CPU使用情况。同vmstat一样&#xff0c;ios…...

【C++】程序员必备知识:认识类与对象

【C】程序员必备知识&#xff1a;认识类与对象 ①.面向过程和面向对象②.类的引入③.类的定义Ⅰ.定义方式Ⅱ.命名规则建议&#xff1a; ④.类的访问限定符及封装Ⅰ.访问限定符Ⅱ.封装 ⑤.类的作用域⑥.类的实例化⑦.类的对象大小计算Ⅰ.如何计算&#xff1f;Ⅱ.类对象存储方式Ⅲ…...

python基础实战5-python基本结构

1 if语句 if语句是用来进行判断的&#xff0c;其使用格式如下 if 要判断的条件&#xff1a; 条件成立时&#xff0c;要做的事情 案例一&#xff1a; age 30 print("------if判断开始------") if age > 18:print("我成年了") print("------if判断…...

移动端异构运算技术 - GPU OpenCL 编程(基础篇)

一、前言 随着移动端芯片性能的不断提升&#xff0c;在移动端上实时进行计算机图形学、深度学习模型推理等计算密集型任务不再是一个奢望。在移动端设备上&#xff0c;GPU 凭借其优秀的浮点运算性能&#xff0c;以及良好的 API 兼容性&#xff0c;成为移动端异构计算中非常重要…...

QString类方法和变量简介(全)

QString类方法和变量简介 操作字符串(|append|insert|sprintf|QString::arg()|prepend|replace|trimmed|simplified)查询字符串(startsWith|endsWith|contains|localeAwareCompare|compare)字符串转换 标准C提供了两种字符串&#xff1a;一种是C语言风格的以"\0"字符…...

中移链控制台对接4A平台功能验证介绍

中移链控制台具备单独的注册登录页面&#xff0c;用户可通过页面注册或者用户管理功能模块进行添加用户&#xff0c;通过个人中心功能模块进行用户信息的修改和密码修改等操作&#xff0c;因业务要求&#xff0c;需要对中移链控制台的用户账号进行集中管理&#xff0c;统一由 4…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...

Python竞赛环境搭建全攻略

Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型&#xff08;算法、数据分析、机器学习等&#xff09;不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...