预防和检测内存泄漏:实用技巧

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。

目录

  • 一、导读
  • 二、概览
  • 三、案例分析
    • 3.1 使用 memory-profiler
    • 3.2 使用MAT(Memory Analyzer)
      • 3.2.1 通过OQL语法
      • 3.2.2 通过 Histogram(直方图)
      • 3.2.3 通过 Dominator Tree(支配树)
      • 3.2.4 通过 leak suspects (泄露疑点)
  • 四、 推荐阅读

在这里插入图片描述
ddd

一、导读

我们继续总结学习Android 基础知识,温故知新。

二、概览

内存泄漏(Memory leak)是指程序在运行过程中分配的内存资源没有被正确释放,导致这部分内存无法再被程序使用,最终消耗了系统的可用内存。

内存泄漏可能会导致以下问题:

  1. 内存耗尽:内存泄漏会导致程序占用的内存越来越多,最终导致系统可用内存耗尽,使程序无法继续运行。
  2. 性能下降:由于内存泄漏的存在,系统中的可用内存减少,导致系统的性能下降,运行速度变慢。
  3. 程序崩溃:当内存泄漏严重时,系统无法分配到足够的内存来执行程序,导致程序崩溃或者无法启动。

内存泄漏的原因可能包括:

  1. 错误的内存分配和释放:程序中可能存在分配内存后未正确释放的情况,导致内存泄漏。
  2. 对象引用未释放:当一个对象的引用无法被正常释放时,其中包含的内存也无法被回收,导致内存泄漏。
  3. 循环引用:两个或多个对象之间互相引用,且没有被其他引用指向时,可能导致内存泄漏。
  4. 缓存未清理:缓存或临时存储的数据长时间保留在内存中,没有及时清理,可能导致内存泄漏。

在开发过程中,可以使用内存分析工具来检测和解决内存泄漏问题,如内存检测工具、代码审查等。

三、案例分析

不同的工具有不同的使用场景,对应线下场景,我们先用 android studio自带的工具,
我们捕获堆转储文件分析

3.1 使用 memory-profiler

//匿名内部类
private Handler mHandler = new Handler(){
    @Override
    public void handleMessage(@NonNull Message msg){
        super.handleMessage(msg);
    }
}

我们先说下原因,匿名内部类默认持有外部类的引用,如果这个mHandler有个延时任务未执行,此时退出activity页面,
此时Handler又持有Activity的引用,导致GC无法回收Activity,导致内存泄漏。

预防和检测内存泄漏:实用技巧_第1张图片

我们大致看下引用链,也能看到泄漏的地方
预防和检测内存泄漏:实用技巧_第2张图片

3.2 使用MAT(Memory Analyzer)

将上面的堆转储另存为 HPROF 文件,再用mat打开

hprof-conv heap-original.hprof heap-converted.hprof

打开后预览页面是这样的,
预防和检测内存泄漏:实用技巧_第3张图片

3.2.1 通过OQL语法

我们直接通过OQL语法来排查内存泄漏,如上图箭头所示的地方,我们在oql页面输入下面的查询代码,然后按下图中红色的小箭头,

select * from instanceof android.app.Activity

会在下面出现查询结果,如下图所示,可以看到,查询到了9个一样的 MemoryShakeActivity,这肯定是有问题的 ,

那我们如何确认是哪里有问题呢?
我们在其中一个activity上右键点击,然后会出现一个菜单,选择 path to gc root, 再选择最长的那个选项 exclude all …
预防和检测内存泄漏:实用技巧_第4张图片

最终,我们在mat里面会出现一个新的页面,也就找到了内存泄漏的地方,看下图:
预防和检测内存泄漏:实用技巧_第5张图片

3.2.2 通过 Histogram(直方图)

它可以列出任意一个类的实例数(每个对象的统计)。它支持使用正则表达式来查找某个特定的类,还可以计算出该类所有对象的保留堆最小值或者精确值,

我们可以通过正则表达式输入 MemoryShakeActivity, 看到Histogram列出了与 MemoryShakeActivity 相关的类

然后选中一行,然后依次选择,点击右键 -> Merge Shortest Paths to GC Roots -> exclude all phantom/weak/soft etc.references(排查虚引用/弱引用/软引用等)
预防和检测内存泄漏:实用技巧_第6张图片

然后我们就可以看到哪里泄漏了

预防和检测内存泄漏:实用技巧_第7张图片

Merge Shortest Paths to GC Roots 可以查看一个对象到RC Roots是否存在引用链相连接,
在JAVA中是通过可达性(Reachability Analysis)来判断对象是否存活,这个算法的基本思想是通过一系列的称谓"GC Roots"的对象作为起始点,
从这些节点开始向下搜索,搜索所走得路径称为引用链,当一个对象到GC Roots没有任何引用链相连则该对象被判定为可以被回收的对象,反之不能被回收,

虚引用/弱引用/软引用的对象可以直接被GC给回收.

3.2.3 通过 Dominator Tree(支配树)

Dominator Tree(支配树)提供了程序中最占内存的对象的排列。

使用方法跟Histogram(直方图)差不多,按照上面类似的操作即可。

3.2.4 通过 leak suspects (泄露疑点)

如下图
预防和检测内存泄漏:实用技巧_第8张图片

四、 推荐阅读

Java 专栏

SQL 专栏

数据结构与算法

Android学习专栏

你可能感兴趣的:(Android学习之路,java,android,性能,面试,内存泄漏)