Android性能优化高阶:卡顿、ANR、死锁,线上如何监控?( 二 )


  1. select 是操作系统提供的系统调用函数,通过它,我们可以把一个文件描述符的数组发给操作系统,让操作系统去遍历,确定哪个文件描述符可以读写,然后告诉我们去处理 。
  2. poll:它和 select 的主要区别就是,去掉了 select 只能监听 1024 个文件描述符的限制
  3. epoll:epoll 主要就是针对select的这三个可优化点进行了改进
1、内核中保存一份文件描述符集合,无需用户每次都重新传入,只需告诉内核修改的部分即可 。2、内核不再通过轮询的方式找到就绪的文件描述符,而是通过异步 IO 事件唤醒 。3、内核仅会将有 IO 事件的文件描述符返回给用户,用户也无需遍历整个文件描述符集合 。
关于epoll机制就总结这么多啦 。
回到 MessageQueue的next 方法,看看哪里可能阻塞
同步屏障消息没移除导致next一直阻塞有一种情况,在存在同步屏障消息的情况下,当异步消息被处理完之后,如果没有及时把同步屏障消息移除,会导致同步消息一直没有机会处理,一直阻塞在nativePollOnce 。
同步屏障消息Android 是禁止App往MessageQueue插入同步屏障消息的,代码会报错
Android性能优化高阶:卡顿、ANR、死锁,线上如何监控?

文章插图
 
系统一些高优先级的操作会使用到同步屏障消息,例如View在绘制的时候,最终都要调用ViewRootImpl的scheduleTraversals方法,会往MessageQueue插入同步屏障消息,绘制完成后会移除同步屏障消息 。
->ViewRootImpl@UnsupportedAppUsagevoid scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;//插入同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);if (!mUnbufferedInputDispatch) {scheduleConsumeBatchedInput();}notifyRendererOfFramePending();pokeDrawLockIfNeeded();}}void unscheduleTraversals() {if (mTraversalScheduled) {mTraversalScheduled = false;//移除同步屏障消息mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);mChoreographer.removeCallbacks(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);}}复制代码为了保证View的绘制过程不被主线程其它任务影响,View在绘制之前会先往MessageQueue插入同步屏障消息,然后再注册Vsync信号监听,Choreographer$FrameDisplayEventReceiver就是用来接收vsync信号回调的
Choreographer$FrameDisplayEventReceiver
private final class FrameDisplayEventReceiver extends DisplayEventReceiverimplements Runnable {...@Overridepublic void onVsync(long timestampNanos, long physicalDisplayId, int frame) {...//mTimestampNanos = timestampNanos;mFrame = frame;Message msg = Message.obtain(mHandler, this);//1、发送异步消息msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);}@Overridepublic void run() {// 2、doFrame优先执行doFrame(mTimestampNanos, mFrame);}}复制代码收到Vsync信号回调,注释1会往主线程MessageQueue post一个异步消息,保证注释2的doFrame优先执行 。
doFrame才是View真正开始绘制的地方,会调用ViewRootImpl的doTraversal、performTraversals,
而performTraversals里面会调用我们熟悉的View的onMeasure、onLayout、onDraw 。


推荐阅读