我知道线程有一个消息队列,处理程序可以将runnables或消息推送到它们,但是当我使用Android Studio工具分析我的android应用程序时,有一个奇怪的过程:
android.os.MessageQueue.nativePollOnce
它比所有其他进程使用CPU更多。它是什么以及如何减少CPU花费的时间? 您可以在下面找到分析器结果。
答案 0 :(得分:26)
简答:
nativePollOnce
方法用于“等待”,直到下一个Message
变为可用。如果在此调用期间花费的时间很长,则您的主(UI)线程无需执行任何实际工作,并等待下一个要处理的事件。没有必要担心这一点。
<强>解释强>
因为“主”线程负责绘制UI并处理各种事件,所以Runnable
有一个处理所有这些事件的循环。
循环由Looper
管理,其工作非常简单:它处理MessageQueue
中的所有消息。
例如,为了响应输入事件,将Message
添加到队列中,作为帧渲染回调甚至是您自己的Handler.post
调用。有时主线程没有工作要做(即队列中没有消息),这可能发生在例如刚完成渲染单帧后(线程刚刚绘制了一帧并准备好下一帧,只需等待一段时间)。 MessageQueue
类中的两个Java方法对我们很有意义:Message next()
和boolean enqueueMessage(Message, long)
。 Message next()
,顾名思义,从队列中获取并返回下一条消息。如果队列为空(并且没有任何内容可以返回),则该方法会调用native void nativePollOnce(long, int)
,这会阻塞,直到添加新消息。此时您可能会问nativePollOnce
如何知道何时醒来。这是一个非常好的问题。将Message
添加到队列时,框架会调用enqueueMessage
方法,该方法不仅会将消息插入队列,还会调用native static void nativeWake(long)
,如果需要唤醒队列。 nativePollOnce
和nativeWake
的核心魔力发生在native (actually, C++) code。 Native MessageQueue使用名为epoll
的Linux系统调用,该调用允许监视IO事件的文件描述符。 nativePollOnce
在某个文件描述符上调用epoll_wait
,而nativeWake
写入描述符,这是IO操作之一,epoll_wait
等待。然后内核从等待状态中取出epoll等待线程,并且线程继续处理新消息。如果您熟悉Java的Object.wait()
和Object.notify()
方法,则可以设想nativePollOnce
与Object.wait()
和nativeWake
相当于Object.notify()
除了它们的实现完全不同之外:nativePollOnce
使用epoll
而Object.wait()
使用futex
Linux调用。值得注意的是,nativePollOnce
和Object.wait()
都没有浪费CPU周期,因为当线程进入任一方法时,它会因线程调度而被禁用(引用Object
类的javadoc)。但是,某些分析器可能会错误地将epoll等待(甚至是对象等待)线程识别为正在运行并消耗CPU时间,这是不正确的。如果这些方法实际上浪费了CPU周期,那么所有空闲应用程序都将使用100%的CPU,加热并降低设备速度。
<强>结论:强>
你不应该担心nativePollOnce
。它只表示已完成所有消息的处理,并且线程等待下一个消息。好吧,这只是意味着你不会给你的主线程太多工作;)