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就会被不停的调度

  • System Server时就会初始化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

导致SWT的原因

1.zygote fork进程卡住

--》线程状态Native,查看是否有Process.zygoteSendArgsAndGetResult,一般是由内存泄漏,内存溢出引起的

2.Dump时间过长

--》 dumpStackTraces 或 dumpStackTraces process

3.SurfaceFlinger过长  

-----》 surfaceflinger hang

4.Binder的Server端卡住

-- >::waitForResponse   IPCThreadState::talkWithDrive

5.Native方法执行时间过长

-->线程状态Native,PowerManagerService.nativeSetAutoSuspend

6.线程死锁

--》blocked 搜索“held by”

7.确认线程关系

--〉线程状态waiting

1.确认是否为watchdog问题

event log搜索"Blocked in"或者"Watchdog" (logcat -b events 、adb logcat -b events -d )

device log搜索"Blocked in",并且找到出问题的blocked thread(adb wait-for-device logcat)

2.查看下device log里面基本trace和cpu使用信息

3.搜索"Cmd line: system_server"检查30s(watchdog half)和60s(watchdog)的trace,假如trace打印的不一样,代表是系统整体慢导致,

4.不是系统性能导致,查看trace发现主要原因

5.可以看的还有,搜索4后出问题的线程log,可以搜索“”pid tid“”,来看是否有线索,搜索sysrq来看thread状态和trace,比如可以看是否在持有mutex锁,在做binder_ioclt操作等等,或者是否处在D状态(不可中断的异常状态)
 

日志

        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 可以快速定位到该线程的函数调用栈:(adb shell ps | grep system_server )

  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异常。​​​​​​​​​​​​​​

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值