博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
句柄泄漏和Handler的底层机制
阅读量:6222 次
发布时间:2019-06-21

本文共 1704 字,大约阅读时间需要 5 分钟。

【简介】

之前在做一个无埋点SDK相关开发的时候,由于上报逻辑比较复杂,故而想到了用hander队列的形式处理事件的上报,但是SDK上线之后,发现出了一个句柄泄漏的bug,百思不得其解,后来看了Handler的底层源码,又做了一些句柄数的追踪和分析,解决了这个问题。

一、Handler在java层的机制如下图,handler的应用层机制很简单,不同的线程通过handler,发送message到messageQueue里面,对应的Looper开启一个死循环,然后一直轮询,如果队列里有待处理的消息,就处理消息;如果没有消息,则开始休眠,节约资源。个中细节就不在赘述,如有需要,可以自行搜索相关资料。复制代码

二、Handler的native层机制我们首先来看Looper.loop()的源码复制代码

我们发现,在这个死循环里,它调用了MessageQueue下的next方法,那么我们再看看这个next方法干了些什么:复制代码

关键方法是这个nativePollOnce():当运行到这里时,会调用native层的方法,系统去轮询一次,如果MessageQueue当前没有要处理的Message,则线程休眠,不占用资源,这里为什么休眠不会产生ANR呢,我们后面会分析。我们现在注意一下nextPollTimeoutMillis这个变量,这个变量代表MessageQueue下次被唤醒的时间。我们知道,MessageQueue里Message在加入队列的时候,会按照执行的时间顺序排列;每次消息入队列时,MessageQueue都会尽量计算出一个精确的时间,假如这个时间是计算出来是2000ms,此时消息队列中没有消息需要马上处理时,会判断用户是否设置了Idle Handler,如果有的话,则会尝试处理mIdleHandlers中所记录的所有Idle Handler,此时会逐个调用这些Idle Handler的queueIdle()成员函数,只会会再次调用nativePollOnce()方法,线程阻塞住,不占用资源。当时间到了,会往管道流中写入字节流,唤醒线程,处理Message。我们知道,安卓的底层是Linux系统。当Looper休眠时,用的是底层的epoll机制来完成阻塞动作,故而不会产生ANR。源码的唤醒调用如图:复制代码

最终调用了Looper.cpp源码的wake()方法复制代码

我们可以看到,唤醒只是往管道流里写了一个"w"的字符流。所以唤醒机制,我们可以直观的理解为:复制代码

在Linux底层,每个线程所能操作的句柄上限是1024个,一旦超过了这个值,则会报句柄泄漏的错误,导致崩溃。所以,是不是我们的上报无埋点的数据时,频繁的休眠唤醒导致句柄数超过了上限呢?三、查看线程的句柄数我们需要一个root了的手机,如果手头没有能用的测试机,可以使用模拟器。我用了一个低版本的模拟器(5.0版本),因为高版本的模拟器也不好直接获取root。我们先要获取进程的id,这个可以通过AS的Logcat查看。之后通过adb shell进入模拟器,cd到/proc/进程id/fd文件夹下,然后ls -al,就可以在Logcat中打印出当前线程所消耗的句柄。如果你没有root权限,fd文件夹是访问不了的。笔者在启动APP后,正常使用了一下APP,接着打印出了当前程序占用的句柄数,发现有800多个句柄开销,大多数是数据库所持有的,搞了半天原来是数据库的问题。但是为了防止意外,笔者已经把SDK中的所有Handler替换掉了。四、总结在android开发中,我们的这些操作会消耗句柄数:1.数据库的读写,不关及时关流会导致句柄开销增大;2.文件流的读写,如果操作不好,也容易导致句柄消耗过大;3.Handler频繁唤醒等。一旦出现句柄泄漏的问题,核心思想就去排查流的读写有没有出问题。因为在安卓底层,Linux对于句柄的操作很多都是通过流来体现的,如果句柄数超过了上限,肯定会出问题。复制代码

转载于:https://juejin.im/post/5b3ad6e6f265da630237241b

你可能感兴趣的文章
[python机器学习及实践(3)]Sklearn实现K近邻分类
查看>>
用pillow和 opencv做透明通道的两图混全(blend)
查看>>
POJ 1002 487-3279
查看>>
netty 4.x 用户手册翻译
查看>>
Acoustic:一个异常强大的wordpress商业模板
查看>>
逆元求法(转)
查看>>
HDU 4162 Shape Number【字符串最小表示】
查看>>
项目Beta冲刺(团队1/7)
查看>>
图片垂直居中的方法(适合只有一行文字和图片)
查看>>
HTTP、HTTP1.0、HTTP1.1、HTTP2.0、HTTPS
查看>>
XML约束技术
查看>>
Ubuntu软件包管理器
查看>>
【03】循序渐进学 docker:基础命令
查看>>
【转】Deep Learning(深度学习)学习笔记整理系列之(四)
查看>>
Protostuff序列化
查看>>
Servlet & Jsp
查看>>
python Image模块基本语法
查看>>
DS博客作业01--日期抽象数据类型设计与实现
查看>>
docker镜像的操作
查看>>
Tomcat 9.0安装配置
查看>>