Android常见内存泄漏场景总结
一、非静态内部类造成的内存泄漏
造成原因:非静态内部类默认会持有外部类的引用,如果内部类的生命周期超过了外部类就会造成内存泄漏。
场景:当Activity销毁后,由于内部类中存在异步耗时任务还在执行,导致Activity实例一直被内部类持有无法被回收,造成内存泄漏
例如:
//TestActivity
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {new Thread(new Runnable() {@Overridepublic void run() {try {//模拟耗时Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}).start();}});
此时点击返回键关闭当前Activity,页面正常回退,但匿名内部类中还有耗时任务执行,如果耗时任务执行完之后要刷新页面还会造成异常导致app闪退。
解决办法:不使用匿名内部类,并且使用static关键字修饰内部类(static修饰的内部类不持有外部类的引用,也自然不会造成上面的内存泄漏),如果内部类中需要使用外部类的资源,可以使用弱引用的方式持有外部类。
优化后的代码如下:
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {new Thread(new MyRunnable()).start();}});static class MyRunnable implements Runnable{@Overridepublic void run() {try {//模拟耗时Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
二、静态成员变量造成的内存泄漏
造成原因:静态成员变量的生命周期 = 应用程序的生命周期,如果该静态成员应用的变量生命周期 < 改静态变量则会造成内存泄漏
场景:静态成员变量持有了一个耗费资源过多的实例(Activity,Fragment)
例如:
public class Person {private static Activity mActivity;Person(Activity activity){mActivity = activity;}
}
此时点击返回键关闭当前Activity,但Person类中的mActivity静态变量持有当前Activity的引用,导致改Activity对象本该被回收而没被回收,导致内存泄漏
解决办法:
- 尽量避免
Static
成员变量引用资源耗费过多的实例(如Context) - 如果必须使用Context,可以使用Application的Context
- 使用弱引用代替强引用持有
三、单例模式造成的内存泄漏
造成原因:单例模式由于其具有静态特性,导致其生命周期 = 应用程序生命周期,如果单例中持有别的类的实例,就会造成内存泄漏
场景:单例模式中持有一个耗费资源过多的实例(Context)
例如:
public class SingleInstance{private static SingleInstance instance;private Context mContext;private SingleInstance(Context context) {this.mContext = context; // 传递的是Activity的context}public SingleInstance getInstance(Context context) {if (instance == null) {instance = new SingleInstance(context);}return instance;}
}
此时由于单例中持有传入的Activity实例,倒是该Activity关闭时,资源得不到回收,从而造成内存泄漏
解决办法:
使用Application的Context代替Activity的Contex
四、Handler造成的内存泄漏
造成原因:当使用非静态内部类(包含匿名内部类)创建Handler时,Handler会持有外部类的对象,如果Handler中还有消息没执行完,此时创建Handler的Activity关闭就会造成内存泄漏。通常由于子线程持有handler的引用(因为要发消息给handler来更新界面),handler又持有activity的引用,从而导致activity不能正常被回收,造成内存泄漏
场景:Activity中通过一个子线程异步请求网络数据,请求成功后更新当前页面。
例如:
//MainActivity.javaprivate Handler mHandler = new Handler(Looper.getMainLooper()){@Overridepublic void handleMessage(Message msg) {//更新页面}};//成功获取到网络数据更新页面private void handleData(String data){Message message = Message.obtain();message.obj = data;mHandler.sendMessage(message);
}
解决办法:
1、静态内部类+弱引用
static class MyHandler extends Handler {WeakReference<Activity > mReference;MyHandler(Activity activity) {mReference= new WeakReference<Activity>(activity);}@Overridepublic void handleMessage(Message msg) {final Activity activity = mReference.get();if (activity != null) {//更新页面}}
}
2、activity销毁时,及时清理消息
@Override
protected void onDestroy() {super.onDestroy();if (mHandler != null) {mHandler.removeCallbacksAndMessages(null);}
}
五、多线程造成的内存泄漏
造成原因:上面一和四其实也是多线程造成内存泄漏的场景,主要是子线程中持有外部类(例如Activity)的引用,让后子线程的生命周期又和Activity不同步,从而造成activity被销毁时子线程中的任务还在执行,从而导致activity的资源迟迟得不到回收造成内存泄漏。
六、集合类造成的内存泄漏
造成原因:当我们把一些对象的引用加入到集合对象(例如常用的ArrayList),当我们不需要改对象时,没有从集合中清理掉改对象的引用,这样集合就会越来越大,如果集合时static的那问题就更严重了。
场景:学生管理系统中需要统计学生信息,使用一个集合存储学生信息,信息统计完成,把信息存入数据库后就不需要学生对象信息了,但是没及时清理掉集合,导致学生对象得不到回收,造成内存泄漏
例如:
// 通过 循环申请Person 对象并放入集合
List<Person> personList = new ArrayList<>();for (int i = 0; i < 10; i++) {Person p = new Person();personList.add(p);
// 虽释放了集合元素引用的本身:p=null
// 但集合List仍然吃药后该对象引用,所以依然不可回收该对象p = null;
}
解决办法:在不使用改集合时,清理集合并把集合置为空
// 释放personList
personList.clear();
personList=null;
七、WebView造成的内存泄漏
造成原因:WebView中可能会进行大量的网络请求,加载大量的资源,从而使得内存占用过高,当我们推出承载Webview的Activity时,没有正确的释放WebView中的资源,导致内存泄漏。
例如:新闻列表页面使用WebView加载一个h5页面,此时会进行大量网络请求加载新闻图片内容,当我们回退该页面时,加载的资源没正确释放导致内存泄漏
解决方案:不使用xml定义webview,通过代码的形式,传入Application的Context然后在承载webview的页面销毁时,释放webview的资源
//代码初始化Webview
mWebView=new WebView(getApplicationContext());
LinearLayout linearLayout = findViewById(R.id.webview);
linearLayout.addView(mWebView);@Override
protected void onDestroy() {if( mWebView!=null) {// 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再// destory()ViewParent parent = mWebView.getParent();if (parent != null) {((ViewGroup) parent).removeView(mWebView);}mWebView.stopLoading();// 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错mWebView.getSettings().setJavaScriptEnabled(false);mWebView.clearHistory();mWebView.clearView();mWebView.removeAllViews();mWebView.destroy();}super.on Destroy();
}
八、资源未释放造成的内存泄漏
造成原因:对于资源的使用(如 广播BraodcastReceiver
、文件流File
、数据库游标Cursor
、图片资源Bitmap
等),若在Activity
销毁时无及时关闭 / 注销这些资源,则这些资源将不会被回收,从而造成内存泄漏
解决方案: 在Activity
销毁时 及时关闭 / 注销资源
关闭资源代码如下:
// 对于 广播BraodcastReceiver:注销注册
unregisterReceiver()// 对于 文件流File:关闭流
InputStream / OutputStream.close()// 对于数据库游标cursor:使用后关闭游标
cursor.close()// 对于 图片资源Bitmap:Android分配给图片的内存只有8M,若1个Bitmap对象占内存较多,当它不再被使用时,应调用recycle()回收此对象的像素所占用的内存;最后再赋为null
Bitmap.recycle();
Bitmap = null;// 对于动画(属性动画)
// 将动画设置成无限循环播放repeatCount = “infinite”后
// 在Activity退出时记得停止动画
参考连接:WebView内存泄漏–解决方法小结 - 简书 (jianshu.com)
https://juejin.cn/post/6844904067534159880
相关文章:
Android常见内存泄漏场景总结
一、非静态内部类造成的内存泄漏 造成原因:非静态内部类默认会持有外部类的引用,如果内部类的生命周期超过了外部类就会造成内存泄漏。 场景:当Activity销毁后,由于内部类中存在异步耗时任务还在执行,导致Activity实…...
未来已来:Angular、React、Vue.js——前端框架的三大巨头
目录 前言 一、Angular框架 特点和优势 核心技术和应用场景 二、React框架 特点和优势 核心技术和应用场景 三、Vue.js框架 特点和优势 核心技术和应用场景 总结: 前言 在Web前端开发领域,随着技术的不断发展,出现了众多优秀的框…...
Mybatis06-动态SQL
动态SQL 1.什么是动态SQL 什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句. 类似JSTL标签 官网描述: MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接…...

26-LINUX--I/O复用-select
一.I/O复用概述 /O复用使得多个程序能够同时监听多个文件描述符,对提高程序的性能有很大帮助。以下情况适用于I/O复用技术: ◼ TCP 服务器同时要处理监听套接字和连接套接字。 ◼ 服务器要同时处理 TCP 请求和 UDP 请求。 ◼ 程序要同时处理多个套接…...

spring源码解析-(2)Bean的包扫描
包扫描的过程 测试代码: // 扫描指定包下的所有类 BeanDefinitionRegistry registry new SimpleBeanDefinitionRegistry(); // 扫描指定包下的所有类 ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(registry); scanner.scan(&quo…...
Java 数学计算 - Random类
在Java中,Random类用于生成伪随机数。这个类在java.util包中,你可以使用它来生成整数、浮点数等不同类型的随机数。以下是关于Random类的一些学习笔记和示例。 1. 创建Random对象 首先,你需要创建一个Random对象。默认情况下,如…...

Ubuntu22.04之解决:无法关机和重启问题(二百四十三)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...

大学数字媒体艺术设计网页设计试题及答案,分享几个实用搜题和学习工具 #媒体#职场发展
现在读书可不像小时候,以前想要校对试题答案,都得找到对应的纸质版答案查看,而且有的还只有答案,没有解析,无法弄清楚答案的由来。但是现在不一样了,现在我们可以通过搜题软件,寻找试题的答案&a…...

【ArcGIS微课1000例】0119:TIFF与grid格式互相转换
文章目录 一、任务描述二、tiff转grid三、grid转tif四、注意事项一、任务描述 地理栅格数据常用TIFF格式和GRID格式进行存储。TIFF格式的栅格数据常以单文件形式存储,不仅存储有R、G、B三波段的像素值,还保存有地理坐标信息。GRID格式的栅格数据常以多文件的形式进行存储,且…...
B3870 [GESP202309 四级] 变长编码
[GESP202309 四级] 变长编码 题目描述 小明刚刚学习了三种整数编码方式:原码、反码、补码,并了解到计算机存储整数通常使用补码。但他总是觉得,生活中很少用到 2 31 − 1 2^{31}-1 231−1 这么大的数,生活中常用的 0 ∼ 100 0…...

WordPress网站更换域名后如何重新激活elementor
在创建WordPress网站时,我们常常需要更改域名。但是,在更换域名后,你可能会遇到一个问题:WordPress后台中的Elementor插件授权状态会显示为不匹配。这时,就需要重新激活Elementor插件的授权。下面我会详细说明如何操作…...
linux cron 执行url
linux cron 执行url 在Linux中,你可以使用curl或wget来执行URL。如果你想要定期执行这个操作,可以使用cron来设置定时任务。 以下是一个使用curl在cron中执行URL的例子: 打开终端。 输入 crontab -e 命令来编辑你的cron作业。 添加一个新…...

压缩视频在线压缩网站,压缩视频在线压缩工具软件
在数字化时代,视频成为了人们记录和分享生活的重要载体。然而,视频文件一般都非常大,这不仅占据了大量的存储空间,也给视频的传输和分享带来了不便。因此,压缩视频成为了许多人必须掌握的技能。本文将详细介绍如何压缩…...

linux经典例题编程
编写Shell脚本,计算1~100的和 首先vi 1.sh,创建一个名为1.sh的脚本,然后赋予这个脚本权限,使用命令chmod 755 1.sh,然后就可以在脚本中写程序,然后运行。 shell脚本内容 运行结果: 编写Shell脚本…...

二叉树的实现(初阶数据结构)
1.二叉树的概念及结构 1.1 概念 一棵二叉树是结点的一个有限集合,该集合: 1.或者为空 2.由一个根结点加上两棵别称为左子树和右子树的二叉树组成 从上图可以看出: 1.二叉树不存在度大于2的结点 2.二叉树的子树有左右之分,次序不能…...

C++笔试强训day41
目录 1.棋子翻转 2.宵暗的妖怪 3.过桥 1.棋子翻转 链接https://www.nowcoder.com/practice/a8c89dc768c84ec29cbf9ca065e3f6b4?tpId128&tqId33769&ru/exam/oj (简单题)对题意进行简单模拟即可: class Solution { public:int dx[…...

【JavaScript】内置对象 - 字符串对象 ⑤ ( 判断对象中是否有某个属性 | 统计字符串中每个字符出现的次数 )
文章目录 一、判断对象中是否有某个属性1、获取对象属性2、判定对象是否有某个属性 二、统计字符串中每个字符出现的次数1、算法分析2、代码示例 String 字符串对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String 一、判…...
Linux环境下测试服务器的DDR5内存性能
要在Linux环境下测试服务器的DDR5内存性能,可以采用以下几种方法和工具: ### 测试原理 内存性能测试主要关注以下几个关键指标: - **带宽**:内存每秒能传输的数据量。 - **延迟**:内存访问请求从发出到完成所需的时间…...

19、matlab信号预处理中的中值滤波(medfilt1()函数)和萨维茨基-戈雷滤波滤(sgolayfilt()函数)
1、中值滤波:medfilt1()函数 说明:一维中值滤波 1)语法 语法1:y medfilt1(x) 将输入向量x应用3阶一维中值滤波器。 语法2:y medfilt1(x,n) 将一个n阶一维中值滤波器应用于x。 语法3:y medfilt1(x,n…...

Scala 练习一 将Mysql表数据导入HBase
Scala 练习一 将Mysql表数据导入HBase 续第一篇:Java代码将Mysql表数据导入HBase表 源码仓库地址:https://gitee.com/leaf-domain/data-to-hbase 一、整体介绍二、依赖三、测试结果四、源码 一、整体介绍 HBase特质 连接HBase, 创建HBase执行对象 初始化…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...

【版本控制】GitHub Desktop 入门教程与开源协作全流程解析
目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork(创建个人副本)步骤 2: Clone(克隆…...

RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
OpenGL-什么是软OpenGL/软渲染/软光栅?
软OpenGL(Software OpenGL)或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式(包括几何处理、光栅化、着色等),不依赖GPU硬件加速。这种模式通常性能较低,但兼容性极强,常用于不支持硬件加速…...