Android性能优化之OOM
OOM
- 什么是OOM?
- 为什么会有OOM?
- APP的内存限制
- App的内存限制是多少?
- 为什么Android系统要设定App的内存限制?
- Android有GC自动回收资源,为什么还会OOM?
- 容易发生OOM的场景及处理方案
- 如何避免OOM?
什么是OOM?
java.lang.OutOfMemoryError
当程序需要申请一段“大”内存时,但是虚拟机没有办法及时的给到,这就会抛出 OutOfMemoryError 也就是OOM
为什么会有OOM?
因为android系统的app的每个进程或者每个虚拟机有个最大内存限制,如果申请的内存资源超过这个限制,系统就会抛出OOM错误。跟整个设备的剩余内存没太大关系。比如比较早的android系统的一个虚拟机最多16M内存,当一个app启动后,虚拟机不停的申请内存资源来装载图片,当超过内存上限时就出现OOM。
APP的内存限制
APP内存由 dalvik内存 和 native内存 两部分组成,dalvik也就是java堆,创建的对象就是在这里分配的,而native是通过c/c++方式申请的内存,Bitmap就是以这种方式分配的。
App的内存限制是多少?
// 以下方法会返回以M为单位的数字,不同的系统平台或设备上的值都不太一样,这里取到是虚拟机的最大内存资源。
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)
int size = activityManager.getMemoryClass();// head堆的大小限制,可以查看/system/build.prop文件
dalvik.vm.heapstartsize = 5m
dalvik.vm.heapgrowthlimit = 48m
dalvik.vm.heapsize = 256m
// heapsize参数表示单个进程heap可用的最大内存,但如果存在以下参数"dalvik.vm.headgrowthlimit=48m"表示单个进程heap内存被限定在48m,即程序运行过程实际只能使用48m内存
为什么Android系统要设定App的内存限制?
- 要使开发者内存使用更为合理。 限制每个应用的可用内存上限,可以放置某些应用程序恶意或者无意的使用过多的内存。而导致其它应用无法正常运行。Android是有多进程的,如果一个进程(一个应用)耗费过多的内存,其他应用就无法运行了。因为有了限制,使得开发者必须好好利用有限资源,优化资源的使用。
- 屏幕显示内容有限,内存足够即可。 即使有万千图片千万数据需要使用到,但在特定时刻需要展示给用户看的总是有限的,因为屏幕显示就那么大,上面可以放的信息就是很有限的。大部分信息都是处于准备显示状态,所以没必要给予太多heap内存。也就是说出现 OOM现象,绝大部分原因是我们的程序设计上有问题,需要优化。优化方法很多,比如通过时间换空间,不停的加载要用的的图片,不停的回收不用的图片,把大图片解析成适合手机屏幕大小的图片等。
- 保证了android的稳定性。 android上的app使用独立虚拟机,每开一个应用就会打开至少一个独立的虚拟机。这样可以避免虚拟机崩溃导致整个系统崩溃,同时代价就是需要浪费更多的内存。
Android有GC自动回收资源,为什么还会OOM?
Android的GC垃圾回收机制会按照特定的算法回收程序不用的内存资源,避免app的内存申请约积越多,但是GC一般回收的资源是那些无主的对象内存或者软引用的资源。
ps:编程要养成习惯,不用的对象设置为null。其实更好的是,不用的图片直接recycle。因为通过设置null让GC来回收,有时候还是会来不及。
容易发生OOM的场景及处理方案
- 网络下载大量图片;
处理方案:多线程异步网络,小图直接用LRUCache+SoftRef+Sd,大图按需下载- 对于需要加载非常多条目信息的ListView,GridView;
处理方案:Google官方推荐使用:“convertview+静态类viewholder”
在adapter的getView函数里有个convertView参数,告知你是否有可重用的view对象。 如果不使用convertView的话,每次调用getView时每次都会重新创建view,这样之前的view可能还没销毁,加之不断的新建view势必会造成内存剧增,从而导致OOM
原因1. 重用缓存convertView传递给getView()方法来避免填充不必要的视图;
2. 使用ViewHolder模式来避免没有必要的调用findViewById;因为太多的findViewById也会影响性能。
ps:ViewHolder类的作用:ViewHolder模式通过在getView方法返回的视图的标签(tag)中存储一个数据结构。这个数据结构包含了指向我们要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById();
如何避免OOM?
避免OOM需要从设计、编码、测试等多个环节综合考虑,持续监控和优化应用的内存使用情况,可以从四个方面着手,首先是减小对象的内存占用,其次是内存对象的重复利用,然后是避免对象的内存泄露,最后是内存使用策略优化
- 图像资源管理
- 图片压缩适当尺寸:使用适当尺寸和质量的图像,避免加载不必要的大图。可以使用第三方库(如Glide、Picasso、Fresco)自动处理图像的压缩、大小调整和缓存;
- 减小Bitmap对象的内存占用:
- inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入;
- decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异。
- 内存泄漏预防
- 考虑使用Application Context而不是Activity Context(避免不经意的Activity泄露);
- 避免静态变量引用Activity或Context:静态变量的生命周期与应用相同,可能导致Activity无法被正常回收;
- 避免在Android里面使用Enum:因为Enum的每个值都是一个对象,会占用额外的内存,并且在运行时会有较大的开销,可能导致应用的内存占用增加和DEX文件大小的增大;
- 避免在onDraw方法里面执行对象的创建:类似onDraw这种频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动;
- 监听器和回调的管理:注册的监听器和回调应在不再需要时及时取消注册;
- Fragment和View的生命周期管理:确保在onDestroy或相应的生命周期方法中清理资源;
- 合理释放资源、销毁对象:在不再需要的时候要及时释放一些资源或销毁对象,尤其是IO流、Bitmap对象、WebView、数据库连接等;
- 谨慎使用static对象:因为static的生命周期过长,和应用的进程保持一致,使用不当很可能导致对象泄漏,在Android中应该谨慎使用static对象;
- 优化布局与视图
- 减少布局层级:扁平化布局,减少嵌套,可以有效降低内存占用,提高渲染效率;
- 避免过度绘制:使用工具检测并消除不必要的重叠绘制区域;
- 内存监控与分析
- 使用Profiler工具:定期使用Android Studio的Profiler工具检查内存使用情况,定位内存泄漏;
- LeakCanary:在开发过程中要注意避免内存泄漏,尤其是长生命周期的对象持有了对Activity或Context的引用,导致Activity无法正常被回收。可以使用工具(如LeakCanary)来帮助检测内存泄漏问题;
- 数据与缓存策略
- 使用更加轻量的数据结构:比如,我们可以考虑使用ArrayMap或SparseArray而不是使用HashMap等传统数据结构。因为ArrayMap是基于数组实现的,而HashMap则是基于哈希表实现的,在存储少量数据时,ArrayMap占用的内存相对较少,因为它通过两个数组来存储键和值,而HashMap则需要维护一个哈希表和链表,这增加了其内存开销。SparseArray更加高效在于他们避免了对key与value的autobox自动装箱,并且避免了装箱后的解箱;
- StringBuilder:在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”;
- 合理使用缓存:对于一些频繁访问的数据,可以使用LruCache来进行内存缓存管理,避免重复的创建和销毁,提高内存利用率(Android自带的Least Recently Used缓存策略);
- 分页加载:对于大量数据,采用分页加载,避免一次性加载所有数据到内存中;
- 内存对象的复用
- 复用系统自带的资源:Android系统本身内置了很多的资源,例如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用。这样做不仅仅可以减少应用程序的自身负重,减小APK的大小,另外还可以一定程度上减少内存的开销,复用性更好;
- 复用View组件:如使用RecyclerView替代ListView,利用ViewHolder模式减少重复创建View对象;
- 多进程与服务优化
- 合理使用多进程:对于内存消耗大的服务或模块,考虑运行在独立进程中,但需注意进程间通信的开销;
- 服务生命周期管理:后台服务应及时停止,避免无谓的内存占用;
- VM(虚拟机)堆大小调整
- 谨慎调整heap size:虽然可以通过android:largeHeap="true"申请更大堆空间,但这不是根本解决方案,且可能导致其他应用或系统性能问题。
借鉴于:https://www.runoob.com/w3cnote/android-oom.html
相关文章:

Android性能优化之OOM
OOM 什么是OOM?为什么会有OOM?APP的内存限制App的内存限制是多少? 为什么Android系统要设定App的内存限制?Android有GC自动回收资源,为什么还会OOM?容易发生OOM的场景及处理方案如何避免OOM? 什么是OOM&am…...

代码随想录算法训练营day7 | 454.四数相加II、383.赎金信、15.三数之和、18.四数之和
文章目录 454.四数相加II思路 383.赎金信思路 15.三数之和思路剪枝去重 18.四数之和思路剪枝去重复习:C中的类型转换方法 总结 今天是哈希表专题的第二天 废话不多说,直接上题目 454.四数相加II 建议:本题是 使用map 巧妙解决的问题&#x…...

Spark实时(三):Structured Streaming入门案例
文章目录 Structured Streaming入门案例 一、Scala代码如下 二、Java 代码如下 三、以上代码注意点如下 Structured Streaming入门案例 我们使用Structured Streaming来监控socket数据统计WordCount。这里我们使用Spark版本为3.4.3版本,首先在Maven pom文件中导…...

《Java初阶数据结构》----4.<线性表---Stack栈和Queue队列>
前言 大家好,我目前在学习java。之前也学了一段时间,但是没有发布博客。时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…...

Android SurfaceFlinger——关联EGL三要素(二十七)
通过前面的文章我们得到了 EGL 的三要素——Display、Surface 和 Context。其中,Display 是一个图形显示系统或者硬件屏幕,Surface 代表一个可以被渲染的图像缓冲区,Context 包含了 OpenGL ES 的状态信息和资源,它是执行 OpenGL 命令的环境。下一步就是调用 eglMakeCurrent…...

Unity3D之TCP网络通信(客户端)
文章目录 概述TCP核心类异步机制 Unity中创建TCP客户端Unity中其它脚本获取TCP客户端接受到的数据后续改进 本文将以Unity3D应用项目作为客户端去连接制定的服务器为例进行相关说明。 Unity官网参考资料: https://developer.unity.cn/projects/6572ea1bedbc2a001ef…...

Kotlin 中 标准库函数
在 Kotlin 中,标准库提供了许多实用的函数,这些函数可以帮助简化代码、提高效率,以下是一些常用的标准库函数及其功能: let: let 函数允许你在对象上执行一个操作,并返回结果。它通常与安全调用操作符 ?. 一起使用&a…...

【教学类-69-01】20240721铠甲勇士扑克牌(随机14个数字+字母)涂色(男孩篇)
背景需求: 【教学类-68-01】20240720裙子涂色(女孩篇)-CSDN博客文章浏览阅读250次。【教学类-68-01】20240720裙子涂色(女孩篇)https://blog.csdn.net/reasonsummer/article/details/140578153 前期制作了女孩涂色延…...

Adobe“加速”创意人士开启设计新篇章
近日,Adobe公司宣布了其行业领先的专业设计应用程序——Adobe Illustrator和Adobe Photoshop的突破性创新。这一重大更新不仅为创意专业人士带来了前所未有的设计可能性和工作效率提升,还让不论是插画师、设计师还是摄影师,都能从中受益并创作…...

释疑 803-(1)概述 精炼提纯版
目录 习题 1-01计算机网络可以向用户提供哪些服务? 1-02 试简述分组交换的要点。 1-03 试从多个方面比较电路交换、报文交换和分组交换的主要优缺点。 1-05 互联网基础结构的发展大致分为哪几个阶段?请指出这几个阶段最主要的特点。 1-06 简述互联网标准制定的几个阶段…...

人工智能与机器学习原理精解【6】
文章目录 数值优化基础理论凹凸性定义在国外与国内存在不同国内定义国外定义总结示例与说明注意事项 国内凹凸性二阶定义的例子凹函数例子凸函数例子 凸函数(convex function)的开口方向凸函数的二阶导数凸函数的二阶定义单变量函数的二阶定义多变量函数…...

JDK、JRE、JVM之间的关系
JDK是Java的开发环境,用JDK开发了JAVA程序后,通过JDK中的编译程序(javac)将java文件编译成字节码文件,作为运行环境的JRE,字节码文件在JRE上运行,作为虚拟机的JVM解析这些字节码,映射…...

redis构建集群时,一直Waiting for the cluster to join
redis构建集群时,一直Waiting for the cluster to join 前置条件参考 前置条件 这是我搭建的集群相关信息,三台虚拟机,分别是一主一从。在将所有虚拟机中redis服务器用到的tcp端口都打开之后,进行构建集群。但是出现上面的情况。 …...

C++之类与对象(2)
前言 今天将步入学习类的默认成员函数,本节讲解其中的构造函数和析构函数。 1.类的默认成员函数 在 C 中,如果一个类没有显式定义某些成员函数,编译器会自动为该类生成默认的成员函数。以下是编译器可能会生成的默认成员函数: 默…...

「树形结构」基于 Antd 实现一个动态增加子节点+可拖拽的树
效果 如图所示 实现 import { createRoot } from react-dom/client; import React, { useState } from react; import { Tree, Input, Button } from antd; import { PlusOutlined } from ant-design/icons;const { TreeNode } Tree; const { Search } Input;const ini…...

ubuntu那些ppa源在哪
Ubuntu中的 PPA 终极指南 - UBUNTU粉丝之家 什么是PPA PPA 代表个人包存档。 PPA 允许应用程序开发人员和 Linux 用户创建自己的存储库来分发软件。 使用 PPA,您可以轻松获取较新的软件版本或官方 Ubuntu 存储库无法提供的软件。 为什么使用PPA? 正如…...

20240724-然后用idea创建一个Java项目/配置maven环境/本地仓储配置
1.创建一个java项目 (1)点击页面的create project,然后next (2)不勾选,继续next (3)选择新项目名称,新项目路径,然后Finsh,在新打开的页面选择…...

PaddleOCR-PP-OCRv4推理详解及部署实现(下)
目录 前言1. 检测模型1.1 预处理1.2 后处理1.3 推理 2. 方向分类器模型2.1 预处理2.2 后处理2.3 推理 3. 识别模型3.1 预处理3.2 后处理3.3 推理 4. PP-OCRv4部署4.1 源码下载4.2 环境配置4.2.1 配置CMakeLists.txt4.2.2 配置Makefile 4.3 ONNX导出4.4 engine生成4.4.1 检测模型…...

【Golang 面试基础题】每日 5 题(二)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...

状态模式与订单状态机的实现
状态模式 状态模式(State Design Pattern)是一种行为设计模式,用于在对象的内部状态改变时改变其行为。这种模式可以将状态的变化封装在状态对象中,使得对象在状态变化时不会影响到其他代码,提升了代码的灵活性和可维…...

【MSP430】MSP430是什么?与STM32对比哪个性能更佳?
一、MSP430是什么? MSP430F5529LP是一款由德州仪器(TI)推出的16位微控制器单元(MCU)开发板,具有USB功能,内存配置为128KB闪存和8KB RAM,工作频率高达25MHz。 这款MCU以其高性能和多…...

Win11 操作(四)g502鼠标连接电脑不亮灯无反应
罗技鼠标连接电脑不亮灯无反应 前言 罗技技术💩中💩,贴吧技术神中神! 最近买了一个g502,结果买回来直接插上电脑连灯都不亮,问了一下客服。客服简单的让我换接口,又是下载ghub之类的…...

自定义QDialog使用详解
自定义QDialog使用详解 一、创建 QDialog 对象二、QDialog设置布局三、QDialog控制模态行为3.1 模态和非模态区别3.2 QDialog的模态使用四、使用 QDialogButtonBox五、处理对话框的结果六、使用 QDialog 的信号和槽QDialog是Qt框架中用于创建对话框窗口的基本类。对话框窗口通常…...

Pytorch使用教学2-Tensor的维度
在PyTorch使用的过程中,维度转换一定少不了。而PyTorch中有多种维度形变的方法,我们该在什么场景下使用什么方法呢? 本小节我们使用的张量如下: # 一维向量 t1 torch.tensor((1, 2)) # 二维向量 t2 torch.tensor([[1, 2, 3], …...

Interesting bug caused by getattr
题意:由 getattr 引起的有趣的 bug 问题背景: I try to train 8 CNN models with the same structures simultaneously. After training a model on a batch, I need to synchronize the weights of the feature extraction layers in other 7 models. …...

获取后端返回的图形验证码
如果后端返回的直接就是一个图形,有以下几种方式展示 一、直接在img标签里面的src里面调用接口 <img :src"dialogSrc" class"photo" alt"验证码图片" click"changeDialog">let orgUrl "/api/captcha" …...

奇怪的Excel单元格字体颜色格式
使用VBA代码修改单元格全部字符字体颜色是个很简单的任务,例如设置A1单元格字体颜色为红色。 Range("A1").Font.Color RGB(255, 0, 0)有时需要修改部分字符的颜色,如下图所示,将红色字符字体颜色修改为蓝色。代码将会稍许复杂&am…...

浅谈芯片验证中的仿真运行之 timescale (五)提防陷阱
一 仿真单位 timeunit 我们知道,当我们的代码中写清楚延时语句时,若不指定时间单位,则使用此单位; 例如: `timescale 1ns/1ps 则 #15 语句表示delay15ns; 例:如下代码,module a 的timescale是1ns/1ps, module b 是1ps/1ps; module b中的clk,频率是由输入参…...

uniapp 重置表单数据
场景 例如有数据如下 data(){return {queryForm:{value1:undefined,}} } 点击重置时候想重置form的数据, 操作 Object.assign(this.$data.queryForm, this.$options.data().queryForm); 就可以重置数据...

自学YOLO前置知识
YOLO前置知识 学习YOLO(You Only Look Once)之前,掌握一些前置知识会帮助你更好地理解和应用该技术。以下是一些推荐的前置知识领域: 计算机视觉基础: 图像处理:了解图像的基本处理技术,如滤波…...