一篇文章搞定《Android内存泄漏》

news2024/11/19 17:20:13

------《Android内存泄漏》

  • 什么是内存泄漏
  • 常见的内存泄漏以及规避方式
    • 单例模式引用Activity
    • 非静态内部类
    • 注册的反注册
    • 定时器Timer
    • WebView的内存泄漏
    • 资源未关闭
    • 属性动画
  • 怎么定位内存泄漏
    • LeakCanary
      • 接入:
      • 使用:
      • 检测:
    • Android Proflier
      • 开始检测:
      • 定位:
    • MAT
      • 下载MAT
      • 配置MAT环境(mac)
      • 用profile获取内存分析文件
      • 打开终端,进行文件转换
      • 打开mat工具,导入我们的-66 文件

什么是内存泄漏

首先我们创建对象的时候比如我们申请一个String类型的List声明为对象A

List A = new ArrayList<>();

这时候等号前面的A,程序会为我们分配到栈中作为引用。
等号后面的new ArrayList,会被我们分配到堆中。

但是由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序卡顿甚至OOM崩溃。此类情况就称为内存泄漏。

常见的内存泄漏以及规避方式

有的同学可能会问JVM有本身的GC机制为什么还会内存泄漏。
虽然有GC机制,但是有些对象在特殊情况下没有满足GC回收条件(引用计数、根搜索)

①:强引用持有的对象。
②:虽然不用这个对象了,但是没释放这个引用导致没有满足GC回收条件。
简单的总结就是:一个对象的引用生命周期超过了本应该存活的存活周期。

单例模式引用Activity

单例模式引用Activity的上下文,单例的生命周期在声明后和应用程序相同。
当Activity关闭时,但是由于单例模式还引用着所以导致不满足GC无法被回收。
解决:用全局的上下文,比如application.getContext。

非静态内部类

非静态内部类(包括匿名内部类)默认就会持有外部类的引用,当非静态内部类被引用导致外部类也无法释放。
典型的就是Handler的使用。很多开发者会去像下面快速的实现Handler的使用:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                // 做相应逻辑
            }
        }
    };
}

当Activity退出后,msg可能仍然存在于消息对列MessageQueue中未处理或者正在处理,那么这样就会导致Activity无法被回收,以致发生Activity的内存泄露
解决:用静态内部类加弱引用(会被GC快速的回收)。去声明我们的Handler

public class MainActivity extends AppCompatActivity {

    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new MyHandler(this);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private static class MyHandler extends Handler {

        private WeakReference<MainActivity> activityWeakReference;

        public MyHandler(MainActivity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = activityWeakReference.get();
            if (activity != null) {
                if (msg.what == 1) {
                    // 做相应逻辑
                }
            }
        }
    }
}

相同的还有内部类造成内存泄露还有一种情况就是使用Thread或者AsyncTask。那么解决方法都是相同的,因为他们的生成原因是相同的。

注册的反注册

比如我们在Activity中注册广播,如果在Activity销毁后不取消注册,那么这个广播会一直存在系统中,同上面所说的非静态内部类一样持有Activity引用,导致内存泄露。同样的问题还会存在一些需要注册和反注册的自定义监听中。
解决:因此注册广播、监听后在Activity销毁后一定要取消注册。

定时器Timer

Timer和TimerTask在Android中通常会被用来做一些计时或循环任务,比如实现无限轮播的ViewPager
解决:当我们Activity销毁的时候要立即cancel掉Timer和TimerTask,以避免发生内存泄漏。

WebView的内存泄漏

关于WebView的内存泄露,因为WebView在加载网页后会长期占用内存而不能被释放,因此我们在Activity销毁后要调用它的destory()方法来销毁它以释放内存。
解决:在销毁WebView之前需要先将WebView从父容器中移除,然后在销毁WebView。

资源未关闭

在使用IO、File流或者Sqlite、Cursor等资源时要及时关闭。这些资源在进行读写操作时通常都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以致发生内存泄露。
解决:因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄露。

属性动画

动画同样是一个耗时任务,比如在Activity中启动了属性动画(ObjectAnimator),但是在销毁的时候,没有调用cancle方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用Activity,这就造成Activity无法正常释放。
解决:因此同样要在Activity销毁的时候cancel掉属性动画,避免发生内存泄漏。

怎么定位内存泄漏

LeakCanary

接入:

因为Leaks会安装到我们的终端上,所以我们只需要在debug时安装,release时不安装
因此需要使用debugImplementation在module的build.gradle中添加一行

debugImplementation ‘com.squareup.leakcanary:leakcanary-android:2.7’

没错,只需要添加这一行就完事了,其他的初始化操作会在LeakCanary库中自动进行。

使用:

LeakCanary启动起来后在Logcat里会有一行日志

D LeakCanary: LeakCanary is running and ready to detect leaks

这说明我们已经将Leaks运行起来了

检测:

我们只需要随意进入一些页面再退出,或者如果想专门查看某一个Activity是否有泄漏,就多次进入这个Activity再退出,过一会后,会弹出一个这样的toast。就说明我们这个页面是有内存泄漏问题的。
在这里插入图片描述
如果没有提示的话,那么我们需要主动打开终端上携带安装的Leaks
进去入口后点击这个Dump Heap Now按钮,也可以立马执行内存分析
在这里插入图片描述
这时候,我们去查看我们的日志台
主要关注Leaking字段
在这里插入图片描述
Leaking有三个状态,代表不同的含义
Leaking:YES:发生了内存泄漏
Leaking:NO:未发生内存泄漏
Leaking:UNKNOW:未知,可能发生泄漏
这里我们的截图显示
在MainActivity2发生了一处内存泄漏,具体位置是在MyHandler,通过这个日志台,我们就可以清楚的知道内存泄漏的情况和具体未知了。
或者在我们的Leaks上也会有日志输出:
在这里插入图片描述
之后我就可以按照提示对我们的内存泄漏问题进行修改了。

Android Proflier

开始检测:

当我们的LeakCanary的信息无法帮我们定位到内存泄漏的位置,但是又提示我们有内存泄漏的。那么我们可以在相关的位置利用Android Proflier进行协助我们定位。
在这里插入图片描述
1、打开我们的Android Studio上工具栏处的Profiler
2、点击加号
3、选择我们要检测的进程
4、绿灯表示正在检测的进程

定位:

双击内存条区域
在这里插入图片描述
出现下面的界面
在这里插入图片描述
这时候去操作你要检测的位置,或者动作。也就是你Leaks提示但是你找不到的区域。
之后多次点击鼠标右键“Force garbage collection”手动回收内存等待几秒
在这里插入图片描述
再右键点击dump java head如果没有的话(高版本的)在左侧会有Capture heap dump之后去进行record
就会进入自动内存泄漏分析界面
选择我们的包名,选择有内存泄露(红色框框标记处)的类或对象
在这里插入图片描述
在这里插入图片描述
有黄色感叹号的“This is 1 leadk”即有内存泄露
最后分析内存泄露源码对象,更改后按照上面步骤重试即可,直至没有泄露。

MAT

下载MAT

下载地址

配置MAT环境(mac)

因为从 android profile直接获取到的hprof文件格式与mat的格式不兼容,所以需要使用工具转换一下
1、打开终端输入:

echo $HOME

2、继续输入:

touch .bash_profile

3、继续输入:

open -e .bash_profile

4、在打开的bash文件中输入:

export PATH=${PATH}:/Users/用户名/你的sdk路径/platform-tools

5、最后输入:

source .bash_profile

用profile获取内存分析文件

在这里插入图片描述
在这里插入图片描述
保存为memory-99.hprof

打开终端,进行文件转换

转换格式 : hprof-conv before.hprof after.hprof
我们这里输入 : hprof-conv memory-99.hprof 66.hprof 能看懂吧,吧我们的源文件 -99 转换成 -66文件

打开mat工具,导入我们的-66 文件

在这里插入图片描述
在这里插入图片描述
点击红框的选项,这个是进行内存泄漏分析的
下面就是这段时间所产生的对象,点击红框 可以直接搜索你要分析的对象
在这里插入图片描述
这里找到了我们的VideoPlayerActivity
鼠标右键选择
在这里插入图片描述
可以看到,意思就是我们排除掉软、弱、虚引用,因为这几种是不会造成内存泄漏的,可以不用管它,我们只需要看排除后还有没引用存在,有的话 那就是强引用了,也就发生了内存泄漏了。
最后得到这样的结果
在这里插入图片描述
然后结合代码分析并解决问题!!至于还有很多可做的一些操作,那就需要自己去发现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux驱动编程(分层分离编程思想)

1、面向对象 ⚫ 字符设备驱动程序抽象出一个 file_operations 结构体&#xff1b; ⚫ 我们写的程序针对硬件部分抽象出 led_operations 结构体。 2、分层 上层实现硬件无关的操作&#xff0c;比如注册字符设备驱动&#xff1a;leddrv.c 下层实现硬件相关的操作&#xff0c;比如…

【R语言】鉴于计算10亿以内训练模型记录for循环的加速

文章目录 1 前言2 几个循环2.1 100以内的和2.2 100以内奇数和/偶数和 3 多重循环3.1 向量化3.2 合并循环3.3 apply函数3.4 矩阵运算3.5 foreach分解任务 4 讨论 1 前言 笔者主力机是MBAM1芯片&#xff08;8256&#xff09;&#xff0c;某个下午巩固循环突然思考到个问题&#…

App违反Google数据安全政策,解决方案

前言 google隐私政策阶段性会进行更新&#xff0c;时长关注隐私政策变化&#xff0c;避免app被强制下架&#xff0c;影响后续运营工作。 邮件内容 摘录邮件详情 我们在以下区域发现了问题&#xff1a; SPLIT_BUNDLE 2:政策声明&#xff0c;数据安全部分&#xff1a;“https:…

中国社科院与美国杜兰大学金融管理硕士项目,引领你走在金融行业前沿

作为金融领域从业人员时刻都在关注行业最新资讯&#xff0c;只有掌握一手的前沿讯息&#xff0c;才能在职场上无往不胜。针对在职的你&#xff0c;如何利用业余时间让自己更增值呢&#xff0c;中国社科院与美国杜兰大学金融管理硕士项目引领你走在金融行业前沿。 金融管理硕士…

ecology9-嵌入第三方系统,特定情况下在嵌套页提示“登录超时,请重新登录”

ecology9-嵌入第三方系统&#xff0c;特定情况下在嵌套页提示“登录超时&#xff0c;请重新登录” 问题描述尝试1尝试2尝试3√尝试4参考 问题描述 A系统对接了ecology9的单点登录。A系统在某个边栏菜单嵌入ecology9的流程页面。当清空浏览器缓存时&#xff0c;A系统在单点登录…

从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题

目录 1. 日期类详细实现 1.1 构造函数和打印函数 1.2 六个比较运算符重载 1.3 日期天数 和 日期天数 1.4 日期 - 天数 和 日期 - 天数 1.5 日期 和 日期 1.6 日期-- 和 --日期 1.7 日期 - 日期 operator- 1.8 打印*this是星期几 2. 日期类完整代码 Date.h: Date.…

计算机智能系统有哪些SCI期刊? - 易智编译EaseEditing

计算机智能系统是计算机科学中的一个重要分支&#xff0c;其主要研究计算机智能和人工智能等方面的问题。以下是一些SCI期刊的推荐&#xff1a; IEEE Transactions on Neural Networks and Learning Systems&#xff1a; 该期刊是IEEE计算智能学会的官方期刊&#xff0c;涵盖了…

JavaWeb——数据链路层详解

目录 一、以太网 1、定义 2、以太网格式帧 二、MTU 1、定义 2、MTU对IP协议的影响 3、MTU对UDP协议的影响 4、MTU对TCP协议的影响 三、ARP协议 1、定义 2、ARP协议的作用 3、ARP协议的工作流程 一、以太网 1、定义 "以太网" 不是一种具体的网络&#xff…

谷歌浏览器 | Chrome DevTools系统学习篇-概述

Chrome DevTools是一套直接内置到谷歌Chrome浏览器的web开发工具。DevTools可以帮助您即时编辑页面并快速诊断问题&#xff0c;最终帮助您更快地构建更好的网站。我们今天的概述主要讲述谷歌浏览器的日常使用和几大常见控制面板的介绍。 目录 1.打开谷歌浏览器 2.谷歌浏览器的…

MySQL 页、页结构、页目录、索引

MySQL中&#xff0c;数据存到了什么地方&#xff1f; 存储到了硬盘的文件上&#xff0c;被称为&#xff1a;数据文件 或 表空间 每个数据库都是由 一组数据文件 组成&#xff0c;这些文件包含了&#xff1a;所有表、索引、其他相关对象的数据 MySQL 以什么样的方式访问&#…

安卓联发科MT6737手机开发核心板 开发模块

MT6737核心板是一款基于联发科MT6737T平台高性能、可运行安卓操作系统的4G智能模块。它支持多种制式&#xff0c;包括LTE-FDD/LTE-TDD/WCDMA/TD-SCDMA/EVDO/CDMA/GSM等。此外&#xff0c;它还支持WiFi 802.11a/b/g/n和BT4.0LE近距离无线通信&#xff0c;并支持GPS/GLONASS/北斗…

机器学习笔记之计算学习理论(二)PAC学习

机器学习笔记之计算学习理论——PAC学习 引言回顾&#xff1a;霍夫丁不等式霍夫丁不等式的问题及其优化 PAC \text{PAC} PAC引出新问题——霍夫丁不等式无法通过直接比较获取最优假设函数问题的解决方法新方法对于霍夫丁不等式的约束证明 总结 引言 上一节从霍夫丁不等式为切入…

STC32G12K128单片机的 moubus-rtu 从机测试工程

简介 STC32G12K128 是STC 推出的一款32位的 C251 的单片机。最近拿到一块官方申请的 屠龙刀-STC32G开发板&#xff0c;就用它的提供的库函数&#xff0c;查考安富莱提供的 modbus 例程移植了一个 modbus-rtu 从站的工程。 modbus-rtu slave 移植注意点 modbus-rtu 功能配置 …

每日学术速递5.3

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Learning Locally Editable Virtual Humans 标题&#xff1a;学习本地可编辑虚拟人 作者&#xff1a;Hsuan-I Ho, Lixin Xue, Jie Song, Otmar Hilliges 文章链接&#xff1a;htt…

【分享】7-Zip解压缩软件的超详细使用攻略

常用的解压缩软件&#xff0c;除了WinRAR之外&#xff0c;7-Zip也是不错的选择。 7-Zip不仅是一款完全免费的开源解压软件&#xff0c;它的解压缩功能也很强大&#xff0c;可以支持视频、文档、文件夹、图片等文件进行压缩操作。 今天小编就来分享一下&#xff0c;7-Zip解压缩…

python一键登录srun校园网(以深圳技术大学为例)

全世界最&#xff08;不&#xff09;好的目录 一、需求分析二、实现过程2.1 分析api2.1.1 连接到校园网&#xff0c;自动弹出登录认证界面2.1.2 先输入错误的账号密码&#xff0c;按F12看会获取哪些信息2.1.3 api 2.2 分析加密2.3 流程总结 三.模拟登录3.1 编写配置文件3.2.功能…

【微软Bing王炸更新】无需等待,人人可用,答案图文并茂,太牛了

&#x1f680; AI破局先行者 &#x1f680; &#x1f332; AI工具、AI绘图、AI专栏 &#x1f340; &#x1f332; 如果你想学到最前沿、最火爆的技术&#xff0c;赶快加入吧✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域优质创作者&#x1f3c6;&am…

opencv实践项目-图像拼接

目录 1.简介2. 步骤2.1 特征检测与提取2.2 关键点检测2.3 关键点和描述符2.4 特征匹配2.5 比率测试2.6 估计单应性 3. 完整代码 1.简介 图像拼接是计算机视觉中最成功的应用之一。如今&#xff0c;很难找到不包含此功能的手机或图像处理API。在本 文中&#xff0c;我们将讨论如…

虹科分享 | 专为创意专业人士设计的Thunderbolt适配器

一、方案介绍 虹科HK-ATTO ThunderLink雷电™ 适配器可以适用于任何地方。 1.小。 2.便携式。 3.强大。 我们的10GBE Thunderbolt适配器的性能至少比内置或附加NIC&#xff08;包括Mac&#xff09;高20% , ATTO 360只需点击一个按钮即可优化以太网SAN&#xff0c;并可与Thunder…

xxl-job 使用示例

目录 介绍 下载源码地址 文档网站 源码导入就是这样目录 数据库建表sql 就这么几个表出来了 修改xxl-job-admin项目下的application.properties文件 完事启动就行了 页面 页面访问地址 账号密码 增加自己的定时任务 介绍 这篇写的是接入使用xxl-job 的一个简单流程…