IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android 性能问题详解 -> 正文阅读

[移动开发]android 性能问题详解

1. 系统的性能

Watchdog机制

Android SWT : Android Software Watchdog Timeout

作用:监控核心服务和核心线程是否卡住,如果判断阻塞 60s ,就会把系统重启,来保证系统恢复正常状态.

  • Monitor Checker,用于检查是Monitor对象可能发生的死锁, AMS, PKMS, WMS等核心的系统服务都是Monitor对象。预警我们不能长时间持有核心系统服务的对象锁,否则会阻塞很多函数的运行

  • Looper Checker,用于检查线程的消息队列是否长时间处于工作状态。Watchdog自身的消息队列,Ui, Io, Display这些全局的消息队列都是被检查的对象。此外,一些重要的线程的消息队列,也会加入到Looper Checker中,譬如AMS, PKMS,这些是在对应的对象初始化时加入的。???????预警我们不能长时间的霸占消息队列,否则其他消息将得不到处理。这两类都会导致系统卡住(System Not Responding)。

  • 对于Looper Checker而言,会判断线程的消息队列是否处于空闲状态。 如果被监测的消息队列一直闲不下来,则说明可能已经阻塞等待了很长时间

  • 对于Monitor Checker而言,会调用实现类的monitor方法,譬如上文中提到的AMS.monitor()方法, 方法实现一般很简单,就是获取当前类的对象锁,如果当前对象锁已经被持有,则monitor()会一直处于wait状态,直到超时,这种情况下,很可能是线程发生了死锁

? ? ? ?只要Watchdog没有发现超时的任务,HandlerChecker就会被不停的调度

  • watchdog的初始化:

    final Watchdog watchdog = Watchdog.getInstance();
    watchdog.start();

    watchdog的添加:

    
    public final class ActivityManagerService extends ActivityManagerNative
            implements Watchdog.Monitor
    
    public void monitor() {
            synchronized (this) { }
        }
    

    watchdog的的检测机制:

  • Watchdog运行后,便开始无限循环,依次调用每一个HandlerChecker的scheduleCheckLocked()方法
  • 调度完HandlerChecker之后,便开始定期检查是否超时,每一次检查的间隔时间由CHECK_INTERVAL常量设定,为30秒
  • 每一次检查都会调用evaluateCheckerCompletionLocked()方法来评估一下HandlerChecker的完成状态:?
    • COMPLETED表示已经完成
    • WAITING和WAITED_HALF表示还在等待,但未超时
    • OVERDUE表示已经超时。默认情况下,timeout是1分钟,但监测对象可以通过传参自行设定,譬如PKMS的Handler Checker的超时是10分钟
  • 如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息
  • 保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal 9

日志

????????adb shell logcat?-b all?

  • event?通过android.util.EventLog工具类打印的日志,一些重要的系统事件会使用此类日志
  • main?通过android.util.Log工具类打印的日志,应用程序,尤其是基于SDK的应用程序,会使用此类日志
  • system?通过android.util.Slog工具类打印的日志,系统相关的日志一般都是使用此类日志,譬如SystemServer
  • radio?通过android.util.Rlog工具类打印的日志,通信模块相关的日志一般都是使用此类日志,譬如RIL

????????binder日志:adb shell cat?/proc/binder

  • failed_transaction_log
  • transaction_log
  • transactions
  • stats

案例1:搜索watchdog发生

watchdog: Blocked in handler XXX # 表示HandlerChecker超时了

watchdog: Blocked in monitor XXX # 表示MonitorChecker超时了

******************************************************************

watchdog杀死系统的日志:

???????Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: XXX
Watchdog: XXX
Watchdog: "*** GOODBYE!

********************************************************************

1.检索到下面信息

W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.wm.WindowManagerService on foreground thread (android.fg)

2.打开system_server进程的traces,检索?android.fg?可以快速定位到该线程的函数调用栈:

  1. "android.fg" prio=5 tid=25 Blocked

  2. | group="main" sCount=1 dsCount=0 obj=0x12eef900 self=0x7f7a8b1000

  3. | sysTid=973 nice=0 cgrp=default sched=0/0 handle=0x7f644e9000

  4. | state=S schedstat=( 3181688530 2206454929 8991 ) utm=251 stm=67 core=1 HZ=100

  5. | stack=0x7f643e7000-0x7f643e9000 stackSize=1036KB

  6. | held mutexes=

  7. at com.android.server.wm.WindowManagerService.monitor(WindowManagerService.java:13125)

  8. - waiting to lock <0x126dccb8> (a java.util.HashMap) held by thread 91

  9. at com.android.server.Watchdog$HandlerChecker.run(Watchdog.java:204)

  10. at android.os.Handler.handleCallback(Handler.java:815)

  11. at android.os.Handler.dispatchMessage(Handler.java:104)

  12. at android.os.Looper.loop(Looper.java:194)

  13. at android.os.HandlerThread.run(HandlerThread.java:61)

  14. at com.android.server.ServiceThread.run(ServiceThread.java:46)

3.由上知道了91进程阻塞,检索?tid=91

  1. "Binder_C" prio=5 tid=91 Native

  2. | group="main" sCount=1 dsCount=0 obj=0x12e540a0 self=0x7f63289000

  3. | sysTid=1736 nice=0 cgrp=default sched=0/0 handle=0x7f6127c000

  4. | state=S schedstat=( 96931835222 49673449591 260122 ) utm=7046 stm=2647 core=2 HZ=100

  5. | stack=0x7f5ffbc000-0x7f5ffbe000 stackSize=1008KB

  6. | held mutexes=

  7. at libcore.io.Posix.writeBytes(Native method)

  8. at libcore.io.Posix.write(Posix.java:258)

  9. at libcore.io.BlockGuardOs.write(BlockGuardOs.java:313)

  10. at libcore.io.IoBridge.write(IoBridge.java:537)

  11. at java.io.FileOutputStream.write(FileOutputStream.java:186)

  12. at com.android.internal.util.FastPrintWriter.flushBytesLocked(FastPrintWriter.java:334)

  13. at com.android.internal.util.FastPrintWriter.flushLocked(FastPrintWriter.java:355)

  14. at com.android.internal.util.FastPrintWriter.appendLocked(FastPrintWriter.java:303)

  15. at com.android.internal.util.FastPrintWriter.print(FastPrintWriter.java:466)

  16. - locked <@addr=0x134c4910> (a com.android.internal.util.FastPrintWriter$DummyWriter)

  17. at com.android.server.wm.WindowState.dump(WindowState.java:1510)

  18. at com.android.server.wm.WindowManagerService.dumpWindowsNoHeaderLocked(WindowManagerService.java:12279)

  19. at com.android.server.wm.WindowManagerService.dumpWindowsLocked(WindowManagerService.java:12266)

  20. at com.android.server.wm.WindowManagerService.dump(WindowManagerService.java:12654)

  21. - locked <0x126dccb8> (a java.util.HashMap)

  22. at android.os.Binder.dump(Binder.java:324)

  23. at android.os.Binder.onTransact(Binder.java:290)

4.解决方法:在这个IO写操作上加一个超时机制,并且这个超时小于Watchdog的超时,不就可以让线程释放它所占有的锁了吗

案例2:

1.检索到

  • 10-14 17:10:51.548 892 1403 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in handler on ActivityManager (ActivityManager)

2.分析出红色的是时间点和进程号,找到trace.txt

3.搜索ActivityManager

  1. "ActivityManager" prio=5 tid=17 TimedWaiting

  2. | group="main" sCount=1 dsCount=0 obj=0x12c0e6d0 self=0x7f84caf000

  3. | sysTid=938 nice=-2 cgrp=default sched=0/0 handle=0x7f7d887000

  4. | state=S schedstat=( 107864628645 628257779012 60356 ) utm=7799 stm=2987 core=2 HZ=100

  5. | stack=0x7f6e68f000-0x7f6e691000 stackSize=1036KB

  6. | held mutexes=

  7. at java.lang.Object.wait!(Native method)

  8. - waiting on <0x264ff09d> (a com.android.server.am.ActivityManagerService$5)

  9. at java.lang.Object.wait(Object.java:422)

  10. at com.android.server.am.ActivityManagerService.dumpStackTraces(ActivityManagerService.java:5395)

  11. at com.android.server.am.ActivityManagerService.dumpStackTraces(ActivityManagerService.java:5282)

  12. at com.android.server.am.ActivityManagerService$AnrActivityManagerService.dumpStackTraces(ActivityManagerService.java:22676)

  13. at com.mediatek.anrmanager.ANRManager$AnrDumpMgr.dumpAnrDebugInfoLocked(SourceFile:1023)

  14. at com.mediatek.anrmanager.ANRManager$AnrDumpMgr.dumpAnrDebugInfo(SourceFile:881)

  15. at com.android.server.am.ActivityManagerService.appNotResponding(ActivityManagerService.java:6122)

  16. - locked <0x21c77912> (a com.mediatek.anrmanager.ANRManager$AnrDumpRecord)

  17. at com.android.server.am.BroadcastQueue$AppNotResponding.run(BroadcastQueue.java:228)

  18. at android.os.Handler.handleCallback(Handler.java:815)

  19. at android.os.Handler.dispatchMessage(Handler.java:104)

  20. at android.os.Looper.loop(Looper.java:192)

  21. at android.os.HandlerThread.run(HandlerThread.java:61)

  22. at com.android.server.ServiceThread.run(ServiceThread.java:46)

4.分析得知AMS设计了一个200毫秒的超时锁。

5.在sys_log中检索”ANR in”关键字或在event_log中检索”anr”关键字

  1. 10-14 17:10:04.215 892 938 E ANRManager: ANR in com.android.systemui, time=27097912

  2. 10-14 17:10:04.215 892 938 E ANRManager: Reason: Broadcast of Intent { act=android.intent.action.TIME_TICK flg=0x50000114 (has extras) }

  3. 10-14 17:10:04.215 892 938 E ANRManager: Load: 89.22 / 288.15 / 201.91

  4. 10-14 17:10:04.215 892 938 E ANRManager: Android time :[2015-10-14 17:10:04.14] [27280.396]

  5. 10-14 17:10:04.215 892 938 E ANRManager: CPU usage from 17016ms to 0ms ago:

  6. 10-14 17:10:04.215 892 938 E ANRManager: 358% 23682/float_bessel: 358% user + 0% kernel

  7. 10-14 17:10:04.215 892 938 E ANRManager: 57% 23604/debuggerd64: 3.8% user + 53% kernel / faults: 11369 minor

  8. 10-14 17:10:04.215 892 938 E ANRManager: 2% 892/system_server: 0.9% user + 1% kernel / faults: 136 minor

2.应用的性能问题

ANR

ANR弹出对话框提示用户

InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒

ContentProvider Timeout :ContentProvider的publish在10s内没进行完
Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕

注意:耗时操作本身是不会产生ANR的,导致ANR的根本还是应用程序无法在一定时间内响应用户的操作。

ANR原因

  • 主线程慢代码

  • 主线程IO

  • 锁竞争

  • 死锁

如何避免ANR

  • 1.UI线程尽量只做跟UI相关的工作
    2.耗时的工作(比如数据库操作,I/O,连接网络或者别的有可能阻碍UI线程的操作)把它放入单独的线程处理
    3.尽量用Handler来处理UI thread和别的thread之间的交互
    4.实在绕不开主线程,可以尝试通过Handler延迟加载
    5.广播中如果有耗时操作,建议放在IntentService中去执行,或者通过goAsync() + HandlerThread分发执行。

Handler机制:

Looper.loop 为什么不会导致死锁?

1.如果不用Looper.loop的话应用也就退出了,代码其实就是在这个循环里面去执行的,固然不会阻塞了

2.主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源

3.若是某个消息处理时间过长,好比你在onCreate(),onResume()里面处理耗时操做,那么下一次的消息好比用户的点击事件不能处理了,整个循环就会产生卡顿,时间一长就成了ANR

总结:Looer.loop()方法可能会引发主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。??????????????

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:02:21  更:2022-03-21 21:04:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:44:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码