Android开发dialog内存泄露,Dialog引发的内存泄漏

article/2025/8/27 22:31:13

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

本文是本人对于 LeakCanary 团队的一篇分析内存泄漏的文章的意译。水平有限,如有不够准确之处,敬请包涵。

主旨:在Lollipop之前的版本,Dialog可能导致内存泄漏。

引言

LeakCanary 提示存在内存泄漏:

GC ROOT thread com.squareup.picasso.Dispatcher.DispatcherThread.

references android.os.Message.obj

references com.example.MyActivity$MyDialogClickListener.this$0

leaks com.example.MyActivity.MainActivity instance `

这段报告是说:一个 Picasso 线程正持有一个位于栈中的 Message 实例的局部变量,而 Message 持有 DialogInterface.OnClickListener 的引用,而 DialogInterface.OnClickListener 又持有一个被销毁 Activity 的引用。

局部变量由于仅存在于栈内,通常存活时间较短。当线程调用某个方法,系统就会为其分配栈帧。当方法返回,栈帧也会随之被销毁,栈内所有局部变量都会被回收。如果局部变量导致了内存泄漏,一般意味着线程死循环或者阻塞了,而且线程在这种状态时持有着 Message 实例的引用。

于是 Dimitris 和我都去 Picasso 源码中一探究竟:

Dispatcher.DispatcherThread 是一个简单的 HandlerThread:

static class DispatcherThread extends HandlerThread {

DispatcherThread() {

super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);

}

}

这个线程通过 Handler 接收 Message,很标准的实现方式:

private static class DispatcherHandler extends Handler {

private final Dispatcher dispatcher;

public DispatcherHandler(Looper looper, Dispatcher dispatcher) {

super(looper);

this.dispatcher = dispatcher;

}

@Override public void handleMessage(final Message msg) {

switch (msg.what) {

case REQUEST_SUBMIT: {

Action action = (Action) msg.obj;

dispatcher.performSubmit(action);

break;

}

// ... handles other types of messages

}

}

}

显然 Dispatcher.DispatcherHandler.handleMessage() 里面没有明显会让本地变量持有 Message 引用的 Bug。

后来出现了越来越多内存泄漏的报告,这些报告不仅来自 Picasso,各种各样线程中的局部变量都存在内存泄漏,而且这些内存泄漏往往和 Dialog 的 click listener 有关。发生内存泄漏的线程有一个共同的特性:它们都是worker thread,而且通过某种阻塞队列接收各自的工作。

看来问题来自于Handler 和 Thread 的工作机制中。

Handler+Thread 工作原理

HandlerThread也是内部封装了Handler的Thread,让我们看看它的工作原理:

for (;;) {

Message msg = queue.next(); //从消息队列中取出消息,可能阻塞

if (msg == null) {

return;

}

msg.target.dispatchMessage(msg);//对应handler处理消息

msg.recycleUnchecked();//清空msg内容、放回消息池中

}

确实有一个本地变量持有 Message 的引用,但它的生命周期本应很短,而且在循环结束时被清除。

我们尝试通过利用阻塞队列实现一个简单的工作者线程来重现这个 Bug,它只发送一个 Message:

void recycleUnchecked() {

// Mark the message as in use while it remains in the recycled object pool.

// Clear out all other details.

flags = FLAG_IN_USE;

what =


http://chatgpt.dhexx.cn/article/0W0YGmml.shtml

相关文章

android源码分析-Dialog

今天给大家介绍android -Dialog源码分析 Dialog 是所有对话框的基类,例如AlertDialog,我们要深入了解指导Dialog的用法,逻辑,必须要把Dilaog弄清楚,下面首先我们来看下Google对Dialog的类描述:/**Base clas…

Dialog源码分析

1, 概述 Dialog(对话框)不仅可以显示信息,还可以和Activity界面进行交互,这种交互是阻塞式的. 继承Dialog的类有好几种,主要以AlertDialog为例来分析一下具体的原理。 2 实现 Dialog依附于Activity来实现,一般在acitivty中显示,因为Dialog的交互是阻塞式的,所以最好另开一线…

爬虫为什么会使用到HTTP代理?

在进行网页爬虫的时候使用HTTP代理,可以进行匿名抓取网页信息,爬取大数据等使用方向。HTTP代理我们很了解,但是你有了解过HTTP协议是什么吗? HTTP协议即超文本传输协议,是Internet上信息传输时使用最为广泛的一种简单…

爬虫笔记——全局代理下的requests写法

当PC挂了全局代理的时候,如果你的requests还像下面写的话,大概率会报错: 正确的写法是:

抓包:Android不走代理的请求

测试用例 测试应用有两个按钮,分别用 HttpURLConnection 和 Okhttp3 请求 https://www.baidu.com/。注意:两个请求都加入了 Proxy.NO_PROXY。 //HttpURLConnection请求https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel13812371237 public …

python爬虫——selenium+chrome使用代理

先看下本文中的知识点: python selenium库安装chrome webdirver的下载安装seleniumchrome使用代理进阶学习 搭建开发环境: selenium库chrome webdirver谷歌浏览器 >7.9 PS:安装了的同学可以跳过了接着下一步,没安装的同学跟…

python 爬虫 客户端_python爬虫

爬虫简介 什么是爬虫? 爬虫:就是抓取网页数据的程序。 HTTP和HTTPS HTTP协议(HyperText Transfer Protocol,超文本传输协议):是一种发布和接收 HTML页面的方法。 HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)简单…

爬虫从入门到精通(7) | 常见反爬-代理IP的使用

目录 一、 为什么要使用代理IP? 二、代理IP的原理 三、代理IP的作用 四、代理IP的分类 ​ 1.根据代理的协议区分 2.根据匿名程度区分 五、在requests模块中如何设置代理 一、 为什么要使用代理IP? 使用自己本地的IP 利用爬虫技术获取某个网站信息的时…

爬虫手册06 代理池和代理服务器搭建

免费代理池的搭建 参考资料:Python3 网络爬虫开发实战(第二版) 一. 学习目标 : 参考《第9章 代理的使用》9.2节搭建自己私有的代理IP池。 二. 实验环境: 阿里云或腾讯云的服务器,我是在打折和新用户优…

我裂开了,教给他如何搭建和使用代理服务器,他居然用来做这么不正经的事(爬虫,代理ip)

代码是正经代码,但是程序员正不正经就不知道了。 ​ 前言 在使用爬虫对某些网站进行爬取时,为了不让网站发现我们的ip,模拟其他用户ip地址去访问网站。也就相当于间接的去访问网站,流程如图: 我们使用到代理服务器&…

Python爬虫进阶 - win和linux下selenium使用代理

目录 Windows selenium配置 下载地址 Chrome Chromedriver 版本对应关系 实践测试 操作元素 浏览器操作 获取元素信息 鼠标操作 实战demo selenium添加代理 Linux selenium配置 检查服务器环境 下载安装第三方库(最简单版) 实践测试 代码…

Python自助爬虫代理ip模块

短小无比的前言: 代理对于爬虫来说可是很重要的一环,尤其在对于大量数据的时候,一不小心自己ip挂了,要么你换网,要么你等个几小时恢复 之后你上网查阅了种种办法,跨越种种艰难险阻,数以堆计的bu…

python爬虫之requests库使用代理方式

在看这篇文章之前,需要大家掌握的知识技能: python基础html基础http状态码 让我们看看这篇文章中有哪些知识点: get方法post方法header参数,模拟用户data参数,提交数据proxies参数,使用代理进阶学习 安装…

爬虫代理IP哪家好?

前言 随着大数据时代的到来,爬虫已经成了获取数据的必不可少的方式,做过爬虫的想必都深有体会,爬取的时候莫名其妙 IP 就被网站封掉了,毕竟各大网站也不想自己的数据被轻易地爬走。 对于爬虫来说,为了解决封禁 IP 的问题,一个有效的方式就是使用代理,使用代理之后可以让…

Python爬虫基础-使用代理

为什么需要代理? 我们爬取数据的时候,开始可以正常爬取,但是过了一段时间,网站可能就会提示“您的IP访问频率过高”,然后就无法正常访问网站。 这是因为网站采取了反爬策略,某个ip访问频率超过一个阈值后&…

Python爬取代理IP

在一些网页的内容爬取过程中,有时候在单位时间内如果我们发送的请求次数过多,网站就可能会封掉我们的IP地址,这时候为了保证我们的爬虫的正常运行,我们就要使用代理IP。 下面来介绍如何构建自己的IP池。 我们用快代理来获取代理i…

流量数据分析的方法学习

1、看数字和趋势(以电商网站为例) 2、维度分解 3、用户分群(又叫用户画像) 4、转化漏斗 5、行为轨迹 关注行为轨迹,是为了真实了解用户行为。通过大数据手段,还原用户的行为轨迹,有助于增长团队…

恶意流量分析(一)

在分析恶意样本时,样本可能包含网络行为,比如样本从C2服务器上请求下载后续病毒文件。所以对于在病毒分析的角度,对恶意流量的分析也是不可避免的。在这里通过恶意流量习题(malware-traffic-analysis)对恶意流量进行入…

APP流量分析

分析参数 发送流量、接收流量 流量统计方法 抓包&#xff1a;干扰因素多&#xff0c;其他APP、安卓自带TCP收发长度统计功能 #找到包名 adb shell pm list packsges -3 #找到UID adb shell ps | grep <包名> #找到目录 adb shell cat /proc/9045<uid>/status #…

如何进行网站流量分析(一)

如何进行网站流量分析&#xff08;一&#xff09; 流量分析整体来说是一个内涵非常丰富的体系&#xff0c;整体过程是一个金字塔结构&#xff1a; 金字塔的顶部是网站的目标&#xff1a;投资回报率&#xff08;ROI&#xff09;。 网站流量分析模型举例 1 网站流量质量分析&a…