android内存泄漏检测,Android内存泄露检测之LeakCanary的使用

news2024/9/29 15:51:53

为了能够简单迅速的发现内存泄漏,Square公司基于MAT开源了LeakCanary。使用LeakCanary,在内存泄漏后,通过分析引用链可以分析内存泄漏的原因,LeakCanary用于检测Activity、Fragment的内存泄漏。

下面通过一些实际案例来进行分析。

1、类编译后结构

非静态成员类的每个实例都隐含着与外层类的一个外层类实例(属性名为this$0)。在非静态成员类实例方法内部,可以调用外层类的方法,或者利用修饰过的this构造获得外层类实例的引用。

当一个类文件编译之后有很多类名字中有$符, 比如Test.class, Test$1.class, Test$2.class, Test$MyTest.class
$后面跟数字的类就是匿名类编译出来的结果。Test$MyTest.class则是内部类MyTest编译后得到的。

在非静态内部类中,我们可以任意使用OuterClass.this来获取外部类实例。

package com.sdcuike.java.nestclass;
 
public class OuterClass {
 
    private static class StaticInnerClass {
 
    }
 
    private class NoStaticInnerClass {
 
    }

编译后,生成的字节码文件:

Compiled from "OuterClass.java"
class com.sdcuike.java.nestclass.OuterClass$NoStaticInnerClass {
  final com.sdcuike.java.nestclass.OuterClass this$0;
}
Compiled from "OuterClass.java"
class com.sdcuike.java.nestclass.OuterClass$StaticInnerClass {
}

1、数据回调匿名内部类泄漏

整个引用链分析,匿名内部类持有外部类引用,外部类通过持有surfaceView间接引用了Activity。匿名内部类里处理数据回调,activity退出了,但是数据回调可能还没停止,从而最终导致Activity泄漏。

public class HXPlaybackTransModel {
    /** surfaceview句柄 */
    private SurfaceView devSurfaceView = null;
public void setParams(){
        //1、修改前代码
            ffmepgPlay.setHikTransDataCallback(new FFMpegAsyncPlayer.GA_SystemTransDataCallback() {
                @Override
                public void onTransStreamDataCallback(int datatype, byte[] pdata, int datalen) {
                    ···
                }
            });
            //2 修改后代码,匿名颞部类改为静态内部类
            ffmepgPlay.setHikTransDataCallback(transDataCallback);
          }
//3 匿名内部类改为静态内部类
    private TransDataCallback transDataCallback = new TransDataCallback(this);

    private static class TransDataCallback implements FFMpegAsyncPlayer.GA_SystemTransDataCallback{

        private WeakReference<HXPlaybackTransModel> playModelRef;

        public TransDataCallback(HXPlaybackTransModel playmodel) {
            this.playModelRef = new WeakReference<>(playmodel);
        }
        @Override
        public void onTransStreamDataCallback(int datatype, byte[] pdata, int datalen) {
            HXPlaybackTransModel playModel = playModelRef.get();
            if (playModel != null){
                //处理具体业务逻辑
            }
        }
    }
}

 修复前后如上所示。

2、SurfaceHolder泄漏

 

public class SurfaceView extends MockView {
//SurfaceHolder是SurfaceView的匿名内部类,所以SurfaceView$4即是指SurfaceHolder。而.this$0即是指其外部类,即SurfaceView。
private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
        @Override
        public boolean isCreating() {
            return false;
        }

        @Override
        public void addCallback(Callback callback) {
        }

···
}
}

 解决方法

// 1、修改前
public class FFMpegAsyncPlayer {
    private SurfaceHolder surfaceHolder;
···
    public void play(String videoPath, Surface surface, SurfaceHolder sfHolder){
        this.surfaceHolder = sfHolder;
        if (ffmpegPlayer != 0){
            play(ffmpegPlayer,videoPath,surface);
        }
    }
}

···
//2 、修改后
public class FFMpegAsyncPlayer {
···
    public void play(String videoPath){
      //1、当前方案已不需要surfaceHolder,调用play方法时,sfHolder可以不传。
        if (ffmpegPlayer != 0){
            play(ffmpegPlayer,videoPath,null);
        }
    }
}

FFMpegAsyncPlayer中会有耗时处理,及处理后的回调,所以会导致持有surfaceHolder,导致最终Activity无法回收。所以对于部分View可能比其所在Acitivity生存时间长的问题要引起注意。可以在子线程操作刷新的View如SurfaceView等几个特例。

实现方案调整,原有方案会持有surfaceHolder,并传给native层进行解码后视频画面渲染。新方案中渲染使用了另一个播放库,已不再需要传入surfaceHolder。所以解决方案,是调用这个方法的时候,不需传入surfaceHolder,FFMpegAsyncPlayer已不需持有其引用。

3、Rxjava Consumer(匿名内部类)导致的泄漏

SurfaceView$4就是SurfaceHolder。

 

每个view都有一个上下文Context,所以SurfaceView的mContext(在继承的View中)最终引用到了其所在的Activity。

CustomSurfaceView继承自SurfaceView。

这个CameraPlaybackCompatPresenter$9匿名内部类究竟在哪里。

点开LeakCanary,看到是一个Rxjava 的Consumer。
具体是哪个,通过debug打断点调试分析找到。

主要原因是其他Rxjava的观察者都通过CompositeDisposable,但dspPlayTimeRefresh并没有加入到其中,导致Activity destroy的时候没有取消其订阅。

CameraPlaybackCompatPresenter{
   /**rxjava取消订阅*/
   private CompositeDisposable mCompositeDisposable = new CompositeDisposable();
//1、clearMessage在Activity 销毁时调用
   public void clearMessage(){
       stopRefreshPlayOsdTime();      // 2、增加的解决方法,取消订阅
       mCompositeDisposable.clear();
   }

   private void stopRefreshPlayOsdTime(){
       if (dspPlayTimeRefresh != null) {
           dspPlayTimeRefresh.dispose();
           dspPlayTimeRefresh = null;
       }
   }

}

 

总结

使用LeakCanary进行内存泄漏分析并不麻烦,将引用链分析清楚,内存泄漏原因自然很快查到。
主要排查思路
1、查看类引用依赖关系
2、引用解除可以在引用链上一个合适节点解除,解决方案并不唯一。

android常见内存泄漏原因:
1、Handler引起的内存泄漏。即使用Handler(非静态内部类)持有外部类(Activity)引用,消息处理不合适导致Activity泄漏。
2、单例模式引起的内存泄漏。例如单例持有Activity上下文导致泄漏。
3、非静态内部类创建静态实例引起的内存泄漏
4、非静态匿名内部类引起的内存泄漏
5、注册/反注册未成对使用引起的内存泄漏。广播接收、EventBus等
6、资源对象没有关闭引起的内存泄漏
7、集合对象没有及时清理引起的内存泄漏

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

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

相关文章

如何替换spring boot中spring框架的版本

背景 我开源的一个项目中&#xff0c;有朋友提到存在Spring Framework 身份认证绕过漏洞(CVE-2023-20860)。 解决方案是升级spring 框架版本&#xff1a; Spring Framework 5.3.X 系列用户建议升级Spring Framework到5.3.26及以上安全版本修复该漏洞Spring Framework 6.0.X 系…

HashMap 学习笔记

HashMap&#xff1a; 为什么经常深入考察&#xff1f; 基于java写的代码会访问很多东西&#xff0c;比如数据库&#xff0c;缓存&#xff0c;消息中间件。 HashMap数据结构 底层是数组 原本已经有很多个位置了 原本是取模但是优化成了性能更高的hash&(n-1) 让哈希值…

【性能测试】5年测试老鸟,总结性能测试基础到指标,进阶性能测试专项......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 性能测试是为了评估…

java 接口,接口的特性,接口实现多态,面向接口编程

package cn.zy.cellphone; /**接口是一种引用数据类型。使用interface声明接口&#xff0c;形式* 形式:public interface 接口名称{}* 接口不能拥有构造方法&#xff0c;不能用于创建对象*接口可以多继承。一个接口可以继承多个其他接口*列如&#xff1a;public interface Broa…

任何人都可以学习车载测试吗?车载测试有什么门槛?

1、车载测试是什么&#xff1f; 车载测试分很多种&#xff0c;有软件测试、硬件测试、性能测试、功能测试等等&#xff0c;每一项测试的内容都不一样&#xff0c;我们所说的车载测试主要指的是汽车软件的功能测试&#xff0c;也就是针对汽车实现的某一个功能&#xff0c;而进行…

windows平台多版本nodejs共存工具nvm-windows 中文文档

2023年4月14日11:11:49 官网地址&#xff1a;https://github.com/coreybutler/nvm-windows 下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases nodejs版本列表 https://nodejs.org/en/download/releases PS C:\Users\pc\Desktop> nvm -h Running ve…

关于测试,我发现了哪些新大陆

关于测试 平常也只是听说过一些关于测试的术语&#xff0c;但并没有使用过测试工具。偶然看到编程老师在课堂上使用龙测为我们展示了一波测试的相关操作&#xff0c;我发现了一些新大陆&#xff0c;这篇文章就记录一下有关测试的相关操作。 开启测试之旅 进入官网了解到 龙测…

java学习之接口二

目录 一、接口vs继承 一、继承 二、接口 二、接口多态特性 一、多态参数 二、多态数组 三、多态传递 三、接口练习 一、接口vs继承 一、继承 package com.hspedu.interface_;public class ExtendsVsInterface {public static void main(String[] args) {LittleMonkey…

5G物理层信道pdcch说明(留档)

网络七层协议OSI是一个开放性的通信系统互连参考模型。 它是国际标准组织制定的一个指导信息互联、互通和写作的网络规范。 开放&#xff1a;是指只要遵循OSI标准&#xff0c;位于世界的任何地方的任何系统之间都可以进行通讯&#xff1b;开放系统&#xff1a;是指遵循互联网协…

【结构型模式】装饰者模式

文章目录优秀借鉴1、概述2、结构3、实现方式3.1、案例引入3.2、实现步骤3.3、案例实现4、装饰者模式优缺点5、结构型模式对比5.1、装饰者模式和代理模式5.2、装饰者模式和适配器模式6、应用场景优秀借鉴 装饰模式 — Graphic Design Patterns设计模式 | 装饰者模式及典型应用黑…

基于图卷积神经网络GCN的二部图链路预测方法实现思路和完整代码【可用于疾病-靶点、miRNA-疾病等相关预测】

本文解决的问题 基本假设&#xff1a;二部图只有邻接矩阵&#xff0c;没有节点特征&#xff0c;并且进行链路预测&#xff0c;有部分链路未知。 如果你有初始节点特征&#xff0c;直接换掉即可 实现思路 这段代码主要是用于构建一个基于图卷积神经网络&#xff08;GCN&#…

内网域渗透总结(红日靶场一)

一、靶场环境搭建 红日靶场&#xff1a;http://vulnstack.qiyuanxuetang.net/vuln/detail/2/靶机通用密码&#xff1a;hongrisec2019win7win2003win2008 这个搭建靶场的过程是我经过实际操作&#xff08;踩坑&#xff09;总结的最简单省事的方式。 首先创建一个仅主机模式的…

使用appuploader工具发布证书和描述性文件教程

使用APPuploader工具发布证书和描述性文件教程 之前用AppCan平台开发了一个应用&#xff0c;平台可以同时生成安卓版和苹果版&#xff0c;想着也把这应用上架到App Store试试&#xff0c;于是找同学借了个苹果开发者账号&#xff0c;但没那么简单&#xff0c;还要用到Mac电脑的…

数据结构之图(最小生成树+最短路径)

基本概念 连通&#xff1a;若a->b存在路径&#xff0c;即为连通 连通图&#xff1a;该图中任意两点均连通&#xff0c;即为连通图 连通分量&#xff1a;下图为无向图&#xff0c;但存在三个连通分量 强连通图&#xff1a;双向的连通图 强连通分量&#xff1a;有向图中的双…

分享一个免梯子智能的问答工具ChatGPT,刷题和学习的好帮手

使用了这个问答工具后,感觉前后端都要被替代了,太强了。 由于本人之前很想体验,但是一直难搞,最近发现了一个免梯子的,重要事情说一遍,免梯子!是我最近发现的最好用,最快的,且不要梯子的,用起来爽,界面也挺好看的,大家快玩儿玩儿。 试了一下写代码,写文案……真棒…

文心一言 VS chatgpt (9)-- 算法导论2.3 7题 3.1 1题

七、描述一个运行时间为O(nlgn)的算法&#xff0c;给定n个整数的集合S和另一个整数&#xff0c;该算法能确定 S中是否存在两个其和刚好为工的元素。 文心一言&#xff1a; 这里是一个运行时间为O(nlgn)的算法&#xff0c;可以用来确定集合 S 中是否存在两个元素&#xff0c;它…

FE_CSS 页面布局之定位

1 为什么需要定位 某个元素可以自由的在一个盒子内移动位置&#xff0c;并且压住其他盒子。 当我们滚动窗口的时候&#xff0c;盒子是固定屏幕某个位置的。 以上效果&#xff0c;标准流或浮动都无法快速实现&#xff0c;此时需要定位来实现。 浮动可以让多个块级盒子一行没有…

第四章 word2vec 的高速化

目录4.1 word2vec 的改进①4.1.1 Embedding 层4.1.2 Embedding 层的实现4.2 word2vec 的改进②4.2.1 中间层之后的计算问题4.2.2 从多分类到二分类4.2.3 sigmoid 函数和交叉熵误差4.2.4 多分类到二分类的实现4.2.5 负采样4.2.6 负采样的采样方法4.2.7 负采样的实现4.3 改进版 w…

组态王与FX5U之间如何快速实现无线通讯?

本方案是基于Modbus RTU协议下实现的1主多从自组网无线通信形式&#xff0c;主站为组态王&#xff0c;从站为两台三菱FX5U PLC。在工厂里&#xff0c;组态王和plc所处位置距离较为分散&#xff0c;重新铺设电缆线工期长&#xff0c;成本高&#xff0c;故采用日系PLC专用无线通讯…

【Halcon 笔记2】参数

一、图形参数 图形参数 Iconic, 包括 image, region, XLD 1.1 image 图像由一个或者多个通道组成&#xff0c;是大小相同的矩阵&#xff0c;包含各种像素类型的灰度值 在图像显示界面&#xff0c;按ctrl健&#xff0c;可以查看当前的像素值 灰度图 一个通道像素点存放在一个…