从LeakCanary看如何判断对象被回收

news2024/12/24 20:54:59

前面已经了解了Service,Fragment,ViewModel对象的销毁时机,那么在触发销毁时机后,我们怎么判断这些对象有没有回收呢?

大家都知道在Java中有强引用,弱引用,软引用,虚引用四种引用方式,而我们判断对象是否回收,就需要通过弱引用来实现,针对弱引用而言。其提供了两种构造方法,如下图所示:

image-20230813162203745

其中我们重点需要关注第二个构造函数,从函数说明可以看出当该弱引用对象创建后,如果该弱引用所引用的对象被GC,则该弱引用对象会被放入给定的ReferenceQueue中,以便系统回收(需注意WeakReference对象和WeakReference引用的对象的区别,前者是WeakReference类的实例,后者是弱引用对象实例,弱引用对象实例在WeakReference的构造函数中传入),这也就意味着我们可以将应该被销毁的对象收集起来,并为他们依此指定ReferenceQueue,通过比对ReferenceQueue中对象情况和我们收集到的对象情况来判断该对象是否被正常销毁。

WeakReference标志化

image-20230813163229106

我们可以看到WeakReference本身是范型对象,这种情况下为了存储多种对象,我们通常会考虑范型T直接指定为Object类型,这也就导致指定WeakReference没办法和其他WeakReference区分,进而进行比较,此时就要求我们要为WeakReference生成唯一标识。

这里我们通过自定义WeakReference来实现,为每一个WeakReference对象赋予一个唯一标识mKey,代码如下:

 public class KeyedWeakReference extends WeakReference {
     private String mKey;
     
 public KeyedWeakReference(String key, Object referent, ReferenceQueue q) {
     super(referent, q);
     mKey = key;
 }
 
 public String getKey() {
     return mKey;
 }
 
 @NonNull
 @Override
 public String toString() {
     return "KeyedWeakReference{ mKey=" + mKey + ",Object=" + get() + " }";
 }
} 

监听对象回收

当某一对象需要回收时,首先我们将该对象包装在WeakHashMap中,以UUID为key,以WeakReference对象为value,随后将该对象的ReferenceQueue指定为我们自定义的,在一段时间后遍历ReferenceQueue,将Queue中存在的所有WeakReference对象按照key从WeakHashMap中移除,HashMap中剩下的就是有可能发生了内存泄漏的对象。

详细的实现代码如下:

 public class ObjectWatcher {
     private static final String TAG = "ObjectWatcher";
     private ReferenceQueue mReferenceQueue;
     private WeakHashMap<String, KeyedWeakReference> mReferences;
     
 private ObjectWatcher() {
     mReferenceQueue = new ReferenceQueue<Object>();
     mReferences = new WeakHashMap<>();
 }
 
 private static volatile ObjectWatcher mInstance;
 public static ObjectWatcher getInstance() {
     if (mInstance == null) {
         synchronized (ObjectWatcher.class) {
             if (mInstance == null) {
                 mInstance = new ObjectWatcher();
             }
         }
     }
     return mInstance;
 }
 
 public void watch(Object object) {
     String key = UUID.randomUUID().toString();
     Log.d(TAG, "watch object:" + object + ",key:" + key);
     KeyedWeakReference weakReference = new KeyedWeakReference(key, object, mReferenceQueue);
     mReferences.put(key, weakReference);
     Handler mainHandler = new Handler(Looper.getMainLooper());
     mainHandler.postDelayed(new Runnable() {
         @Override
         public void run() {
 
             KeyedWeakReference keyedWeakReference = null;
             do {
                 keyedWeakReference = (KeyedWeakReference) mReferenceQueue.poll();
                 Log.d(TAG, "keyedWeakReference:" + keyedWeakReference);
                 if (keyedWeakReference != null) {
                     mReferences.remove(keyedWeakReference.getKey());
                     Log.d(TAG, "object has been destroyed:" + keyedWeakReference.toString());
                 }
             } while (keyedWeakReference != null);
         }
     }, 5000);
 }
}

在上述代码中,我们将需要观察的对象通过watch方法传入,随后创建KeyedWeakReference对象,分别将该对象装入ReferenceQueue(系统底层代码实现)和mReferences WeakHashMap中,随后在5秒后遍历ReferenceQueue,确实监听到了对象被回收,日志打印如下:

image-20230813164420870

结合上文我们就可以判断一个对象是否已经被回收了,当然针对WeakHashMap中仍然存在的对象,我们可以触发一次GC后,再次遍历观察。

为什么是弱引用,相信有熟悉四大引用的朋友,也看到过软引用和虚引用的构造函数,这两种引用的构造函数也可以指定ReferenceQueue,如下图所示:

image-20230813201912910

image-20230813201953656

那么为什么不使用软引用或者虚引用,非要使用弱引用呢?Github issue上也有同样的疑问,如下图:

image-20230813202511693

从图中可以看到,这里主要的考虑应该是触发的频次,对于弱引用而言,其在下次GC时就会触发。

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

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

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

相关文章

2、手写模拟Spring底层原理

创建BeanDefinition bean定义 设置BeanDefinition 的类信息&#xff0c;作用域信息 创建beanDefinitionMap scope为原型&#xff1a; scope为单例&#xff1a; 总结&#xff1a; 扫描ComponentScan注解上的包扫描路径&#xff0c;将Component注解修饰的类&#xff0c;生成Bea…

数据结构之并查集

并查集 1. 并查集原理2. 并查集实现3. 并查集应用3.1 省份数量3.2 等式方程的可满足性 4. 并查集的优缺点及时间复杂度 1. 并查集原理 并查表原理是一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题。并查集的思想是用一个数组表示了整片森林&#xff0…

Apache Doris 极简运维之BE扩缩容(1)

Apache Doris 极简运维之BE扩缩容&#xff08;1&#xff09; 一、环境信息硬件信息软件信息 二、缩容2.1 DROP BACKEND缩容2.2 DECOMMISSION BACKEND缩容2.2.1 缩容前2.2.2 缩容中2.2.3 缩容后 三、扩容3.1 扩容前3.2 扩容中3.3 扩容后 四、总结 一、环境信息 已部署三个BE节点…

十二、Linux如何修改文件/文件夹所属用户or用户组?chown命令

目录 1、基础语法 2、修改目标用户&#xff1a; 3、修改用户组&#xff1a; 4、使用-R命令&#xff0c;并同时修改用户/用户组 1、基础语法 chown [-R] [目标用户][:][目标用户组] 被修改文件/文件夹 &#xff08;1&#xff09;选项-R&#xff1a;同chmod&#xff0c;对文…

Yellowbrick新手入门简介:用于Python机器学习模型可视化的工具库

Yellowbrick 是一个新的 Python 库&#xff0c;它扩展了 Scikit-Learn API&#xff0c;将可视化合并到机器学习工作流程中。 Yellowbrick需要依赖诸多第三方库&#xff0c;包括Scikit-Learn&#xff0c;Matplotlib&#xff0c;Numpy等等。 Yellowbrick 是一个开源的纯 Python…

resource doesn‘t have a corresponding Go package.

resource doesnt have a corresponding Go package. GO这个鬼东西不能直接放src下。 ************ Building Go project: ProjectGoTest ************with GOPATH: D:\Go;D:\eclipse-jee-oxygen-2-win32-x86_64\workspace\ProjectGoTest >> Running: D:\Go\bin\go.exe …

项目管理实战笔记1:项目管理常识

序 看了下极客时间的《项目管理实战》&#xff0c;觉得跟之前学习PMP的标准资料还是有所侧重。重新整理下&#xff0c;相比书上繁杂的知识&#xff0c;这个更通俗易懂。 1 角色转换&#xff1a;三大误区 误区1&#xff1a;事必躬亲 自己做事情是可控的&#xff0c;做项目依赖…

树莓派第一讲:入门那些事(系统烧录、外设连接)

目录 基本了解&#xff1a; 系统烧录&#xff1a; 连接外设&#xff1a; 基本了解&#xff1a; 树莓派4B是一款单板计算机&#xff0c;采用ARM架构处理器&#xff0c;配备4GB内存、Gigabit以太网口、多个USB接口、HDMI输出接口等。它具备1.5Ghz运行的64位四核处理器&#x…

通过安全日志读取WFP防火墙放行日志

前言 之前的文档中&#xff0c;描写了如何对WFP防火墙进行操作以及如何在防火墙日志中读取被防火墙拦截网络通讯的日志。这边文档&#xff0c;着重描述如何读取操作系统中所有被放行的网络通信行为。 读取系统中放行的网络通信行为日志&#xff0c;在win10之后的操作系统上&am…

vmware17 开启虚拟化

前言 有时候需要在虚拟机上安装虚拟机&#xff0c;方便做一些测试 解决办法 在vmware17 上对虚拟机开启虚拟化即可 下图中都勾上即可 设置完成之后就可以在虚拟机上安装虚拟机

【LLM评估篇】Ceval | rouge | MMLU等指标

note 一些大模型的评估模型&#xff1a;多轮&#xff1a;MTBench关注评估&#xff1a;agent bench长文本评估&#xff1a;longbench&#xff0c;longeval工具调用评估&#xff1a;toolbench安全评估&#xff1a;cvalue&#xff0c;safetyprompt等 文章目录 note常见评测benchm…

18.安全机制

文章目录 安全机制认证&#xff08;Authentication&#xff09;鉴权&#xff08;Authorization&#xff09;概念和组成创建Role和ClusterRole创建RoleBinding 和ClusterRoleBindingResources 准入控制&#xff08;Admission Control&#xff09;实验&#xff1a;创建一个用户管…

模型微调(fine-tune)

一、关于模型微调的一些基础知识 1、模型微调&#xff08;fine-tune&#xff09; 微调(fine-tune)通过使用在大数据上得到的预训练好的模型来初始化自己的模型权重&#xff0c;从而提升精度。这就要求预训练模型质量要有保证。微调通常速度更快、精度更高。当然&#xff0c;自己…

解放数据库,实时数据同步利器:Alibaba Canal

文章首发地址 Canal是一个开源的数据库增量订阅&消费组件&#xff0c;主要用于实时数据同步和数据订阅的场景&#xff0c;特别适用于构建分布式系统、数据仓库、缓存更新等应用。它支持MySQL、阿里云RDS等主流数据库&#xff0c;能够实时捕获数据库的增删改操作&#xff…

nvm的安装配置(node多版本切换控制)

安装 1. 首先要先卸载已安装的node 找到node&#xff0c;卸载就可以。 2. 下载 NVM 直接进入安装包下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases&#xff0c;选择 nvm-setup.zip&#xff0c;下载后直接安装。 3. 配置环境变量(有的电脑会配好…

linux学习(文件系统+inode)[14]

输出重定向可分离 stdout -> 1printf("hello printf 1\n");fprintf(stdout,"hello fprintf 1\n");// stderr -> 2errno 1;perror("hello perror 2"); //stderrconst char *s1 "hello write 1\n";write(1, s1, strlen(s1));con…

PV3D: A 3D GENERATIVE MODEL FOR PORTRAITVIDEO GENERATION 【2023 ICLR】

ICLR&#xff1a;International Conference on Learning Representations CCF-A 国际表征学习大会&#xff1a;深度学习的顶级会议 生成对抗网络(GANs)的最新进展已经证明了生成令人惊叹的逼真肖像图像的能力。虽然之前的一些工作已经将这种图像gan应用于无条件的2D人像视频生…

人工智能轨道交通行业周刊-第56期(2023.8.14-8.20)

本期关键词&#xff1a;数字化建设、巡检机器人、智慧城轨、福州地铁4号线、避雷器、LangChain 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMet…

vactor中迭代器失效问题

目录 什么是迭代器失效导致迭代器失效的操作VS和g环境下对与迭代器失效的态度 什么是迭代器失效 迭代器的底层其实就是一个指针&#xff0c;或者对指针进行了封装 vector的迭代器就是一个指针T* 一个迭代器指向某一个空间&#xff0c;此时这块空间被释放了&#xff0c;这个迭…

【Spring Boot】详解条件注解以及条件拓展注解@Conditional与@ConditionOnXxx

Spring Conditional Spring 4.0提供的注解。作用是给需要装载的Bean增加一个条件判断。只有满足条件才会装在到IoC容器中。而这个条件可以由自己去完成的&#xff0c;可以通过重写Condition接口重写matches()方法去实现自定义的逻辑。所以说这个注解增加了对Bean装载的灵活性。…