Android面试中常问的ANR问题

1.ANR定义

Android应用的主线程处于阻塞状态的时间过长,触发"Application not Responding"(Anr)的错误.如果应用处于前台,会有弹窗.

2.ANR发生的原因

1.主线程耗时操作
2.主线程被子线程同步锁lock
3.主线程被binder对端阻塞
4.binder线程被沾满
5.得不到系统资源

3.ANR的几种类型

1.Service TimeOut超时
超时原因:
在执行服务的生命周期方法:oncreate ,onstart onbind的时候超时
超时时间: 前台服务20s,后台服务200s
2.BroadCast TimeOut广播超时
超时原因:
在指定的时间,onReceive方法执行超时
超时时间: 前台10s,后台60s
3.InputDispatching Timeout
输入事件超时,如点击,触摸事件无响应
超时时间:5s

ServiceTimeout触发机制

bumpServiceExecutingLocked();埋入炸弹,对应的生命周期在对应的时间内没有执行完,就会anr,如果处理完会removemsg
发送

 void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        mAm.mHandler.sendMessageDelayed(msg,
                proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    }

处理SERVICE_TIMEOUT_MSG消息

com.android.server.am.ActivityManagerService#SERVICE_TIMEOUT_MSG
  case SERVICE_TIMEOUT_MSG: {
                mServices.serviceTimeout((ProcessRecord)msg.obj);
            } break;
//日志里的第一现场:Timeout executing service
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(timeout);
timeout.dump(pw, "    ");
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
 anrMessage = "executing service " + timeout.shortInstanceName;

BroadCast Timeout 触发机制:

广播分为:串行,并行
引发超时的广播是串行广播:
动态注册的有序广播
静态注册广播

2.ANR定位流程

1.通过logcat查看ANR in 查看cpu信息和系统负载情况
apk包名,进程号,触发ANR的原因,系统在发生ANR的时间段的各个应用的cpu使用情况
如input超时,ANR根据超时时间,往前推5s,使用application is not responding过滤,过滤monkey日志

2.找到anr的log日志,检查主线程main的trace日志信息
/data/anr
3.定位发生ANR的具体时段
4.检查ANR发生时间段内系统的状态

3.避免ANR的方法:减少主线程耗时操作

1.ServiceTimeout
避免application oncreate耗时
避免service生命周期耗时
可以使用IntentService
2.BroadCastTimeout
可以使用IntentService
3.InputDispatching Timeout
避免主线程耗时

4.合理的性能优化也能够避免

1.避免while或ondraw 中new 对象
2.使用对象池 Android.util.Pools
3.检查多余的背景图片,特别是父布局的背景图片
4.减少布局层级:constrainlayout,merge
5.延时加载布局viewstub

4.ANR检测工具

blockcanary
strictmode
leakcanary

猜你喜欢

转载自blog.csdn.net/github_37610197/article/details/125109776