Android中ANR的分析和解决
一 ANR概述
2、ANR的类型
(1)KeyDispatchTimeout(常见)
input事件在5S内没有处理完成发生了ANR。
logcat日志关键字:Input event dispatching timed out
(2)BroadcastTimeout
前台Broadcast:onReceiver在10S内没有处理完成发生ANR。
后台Broadcast:onReceiver在60s内没有处理完成发生ANR。
logcat日志关键字:Timeout of broadcast BroadcastRecord
(3)ServiceTimeout
前台Service:onCreate,onStart,onBind等生命周期在20s内没有处理完成发生ANR。
后台Service:onCreate,onStart,onBind等生命周期在200s内没有处理完成发生ANR
logcat日志关键字:Timeout executing service
(4)ContentProviderTimeout
ContentProvider 在10S内没有处理完成发生ANR。
logcat日志关键字:timeout publishing content providers
3、ANR出现的原因
(1)主线程频繁进行耗时的IO操作:如数据库读写
(2)多线程操作的死锁,主线程被block;
(3)主线程被Binder 对端block;
(4)System Server中WatchDog出现ANR;
(5)service binder的连接达到上线无法和和System Server通信
(6)系统资源已耗尽(管道、CPU、IO)
4、如何分析ANR
(1)日志分析:ANR发生时都会在log中输出错误信息,从log中可以获得ANR的类型,CPU的使用情况,CPU使用率过高有可能是CPU饥饿导致了ANR。CPU使用率过低说明主线程被block了,如果IOwait高是因为主线程进行I/O操作造成的。
(2)traces文件分析:除了log输出外,你会发现各个应用进程和系统进程的函数堆栈信息都输出到了一个/data/anr/traces.txt的文件中,这个文件是分析ANR原因的关键文件.要获取到该文件可使用adb指令进行赋权后拉出查看调用stack。通过log、trace.text、代码结合分析ANR的成因(iowait?Memoryleak?Block?)
(3)traces文件无法分析的:不过还存在一些ANR问题,trace文件是分析不了的,例如我们的系统上,人脸识别活体攻击的时候,native算法耗尽cpu资源导致其他app无法抢占cpu时间片导致anr,假如ANR的app是你开发的,估计查到死也找不到问题所在,类似这类问题也写过简要的分析文章:
接下来我们将一步一步分析ANR,这个过程能让我们进一步明白如何找到问题、分析问题以及解决问题
二 ANR发生时信息收集
ProcessRecord.ProcessErrorStateRecord.appNotResponding
final void appNotResponding(ProcessRecord app, ActivityRecord activity,ActivityRecord parent, boolean aboveSystem, final String annotation) {......updateCpuStatsNow(); //第一次 更新cpu统计信息synchronized (this) {//PowerManager.reboot() 会阻塞很长时间,因此忽略关机时的ANRif (mShuttingDown) {return;} else if (app.notResponding) {return;} else if (app.crashing) {return;}//记录ANR到EventLogEventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,app.processName, app.info.flags, annotation);// 将当前进程添加到firstPidsfirstPids.add(app.pid);int parentPid = app.pid;//将system_server进程添加到firstPidsif (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);for (int i = mLruProcesses.size() - 1; i >= 0; i--) {ProcessRecord r = mLruProcesses.get(i);if (r != null && r.thread != null) {int pid = r.pid;if (pid > 0 && pid != app.pid &&pid != parentPid && pid != MY_PID) {if (r.persistent) {firstPids.add(pid); //将persistent进程添加到firstPids} else {lastPids.put(pid, Boolean.TRUE); //其他进程添加到lastPids}}}}}// 记录ANR输出到main logStringBuilder info = new StringBuilder();info.setLength(0);info.append("ANR in ").append(app.processName);if (activity != null && activity.shortComponentName != null) {info.append(" (").append(activity.shortComponentName).append(")");}info.append("\n");info.append("PID: ").append(app.pid).append("\n");if (annotation != null) {info.append("Reason: ").append(annotation).append("\n");}if (parent != null && parent != activity) {info.append("Parent: ").append(parent.shortComponentName).append("\n");}//创建CPU tracker对象final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);//输出traces信息【见小节2】File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, NATIVE_STACKS_OF_INTEREST);updateCpuStatsNow(); //第二次更新cpu统计信息//记录当前各个进程的CPU使用情况synchronized (mProcessCpuTracker) {cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);}//记录当前CPU负载情况info.append(processCpuTracker.printCurrentLoad());info.append(cpuInfo);//记录从anr时间开始的Cpu使用情况info.append(processCpuTracker.printCurrentState(anrTime));//输出当前ANR的reason,以及CPU使用率、负载信息Slog.e(TAG, info.toString()); //将traces文件 和 CPU使用率信息保存到dropbox,即data/system/dropbox目录addErrorToDropBox("anr", app, app.processName, activity, parent,annotation, cpuInfo, tracesFile, null);synchronized (this) {...//后台ANR的情况, 则直接杀掉if (!showBackground && !app.isInterestingToUserLocked() &&app.pid != MY_PID) {app.kill("bg anr", true);return;}//设置app的ANR状态,病查询错误报告receivermakeAppNotRespondingLocked(app,activity != null ? activity.shortComponentName : null,annotation != null ? "ANR " + annotation : "ANR",info.toString());//重命名trace文件String tracesPath =SystemProperties.get("dalvik.vm.stack-trace-file", null);if (tracesPath != null && tracesPath.length() != 0) {//traceRenameFile = "/data/anr/traces.txt"File traceRenameFile = new File(tracesPath);String newTracesPath;int lpos = tracesPath.lastIndexOf (".");if (-1 != lpos)// 新的traces文件= /data/anr/traces_进程名_当前日期.txtnewTracesPath = tracesPath.substring (0, lpos) +"_" + app.processName + "_" + mTraceDateFormat.format(new Date()) +tracesPath.substring (lpos);elsenewTracesPath = tracesPath + "_" + app.processName;traceRenameFile.renameTo(new File(newTracesPath));}//弹出ANR对话框Message msg = Message.obtain();HashMap<String, Object> map = new HashMap<String, Object>();msg.what = SHOW_NOT_RESPONDING_MSG;msg.obj = map;msg.arg1 = aboveSystem ? 1 : 0;map.put("app", app);if (activity != null) {map.put("activity", activity);}//向ui线程发送,内容为SHOW_NOT_RESPONDING_MSG的消息mUiHandler.sendMessage(msg);}}
ANR的信息收集过程中讲到当ANR发生的时候,系统会调用如下相关的关键函数代码,来将系统当前的关键信息保存到日志当。当ANR发生的时候,会将ANR记录到event log和main log中。
三 ANR日志分析
3.1 查看events_log
查看mobilelog文件夹下的events_log,从日志中搜索关键字:am_anr,找到出现ANR的时间点、进程PID、ANR类型。
如日志:
07-20 15:36:36.472 1000 1520 1597 I am_anr : [0,1480,com.xxxx.moblie,952680005,Input dispatching timed out (AppWindowToken{da8f666 token=Token{5501f51 ActivityRecord{15c5c78 u0 com.xxxx.moblie/.ui.MainActivity t3862}}}, Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)]
从上面的log我们可以看出: 应用com.xxxx.moblie 在07-20 15:36:36.472时间,发生了一次KeyDispatchTimeout类型的ANR,它的进程号是1480.
把关键的信息整理一下:
- ANR时间:07-20 15:36:36.472
- 进程pid:1480
- 进程名:com.xxxx.moblie
- ANR类型:KeyDispatchTimeout
我们已经知道了发生KeyDispatchTimeout的ANR是因为 input事件在5秒内没有处理完成。那么在这个时间07-20 15:36:36.472 的前5秒,也就是(15:36:30 ~15:36:31)时间段左右程序到底做了什么事情?这个简单,因为我们已经知道pid了,再搜索一下pid = 1480的日志.这些日志表示该进程所运行的轨迹,关键的日志如下:
07-20 15:36:29.749 10102 1480 1737 D moblie-Application: [Thread:17329] receive an intent from server, action=com.ttt.push.RECEIVE_MESSAGE
07-20 15:36:30.136 10102 1480 1737 D moblie-Application: receiving an empty message, drop
07-20 15:36:35.791 10102 1480 1766 I Adreno : QUALCOMM build : 9c9b012, I92eb381bc9
07-20 15:36:35.791 10102 1480 1766 I Adreno : Build Date : 12/31/17
07-20 15:36:35.791 10102 1480 1766 I Adreno : OpenGL ES Shader Compiler Version: EV031.22.00.01
07-20 15:36:35.791 10102 1480 1766 I Adreno : Local Branch :
07-20 15:36:35.791 10102 1480 1766 I Adreno : Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.UM.6.4.R1.08.00.00.309.049
07-20 15:36:35.791 10102 1480 1766 I Adreno : Remote Branch : NONE
07-20 15:36:35.791 10102 1480 1766 I Adreno : Reconstruct Branch : NOTHING
07-20 15:36:35.826 10102 1480 1766 I vndksupport: sphal namespace is not configured for this process. Loading /vendor/lib64/hw/gralloc.msm8998.so from the current namespace instead.
07-20 15:36:36.682 10102 1480 1480 W ViewRootImpl[MainActivity]: Cancelling event due to no window focus: KeyEvent { action=ACTION_UP, keyCode=KEYCODE_PERIOD, scanCode=0, metaState=0, flags=0x28, repeatCount=0, eventTime=16099429, downTime=16099429, deviceId=-1, source=0x101 }
从上面我们可以知道,在时间 07-20 15:36:29.749 程序收到了一个action消息。
07-20 15:36:29.749 10102 1480 1737 D moblie-Application: [Thread:17329] receive an intent from server, action=com.ttt.push.RECEIVE_MESSAGE。
原来是应用com.xxxx.moblie 收到了一个推送消息(com.ttt.push.RECEIVE_MESSAGE)导致了阻塞,我们再串联一下目前所获取到的信息:在时间07-20 15:36:29.749 应用com.xxxx.moblie 收到了一下推送信息action=com.ttt.push.RECEIVE_MESSAGE发生阻塞,5秒后发生了KeyDispatchTimeout的ANR。
3.2 查看main_log日志信息
在分析ANR的时候,我们首先要确认是不是当时CPU很紧张、各路APP都在抢占资源,CPU无法及时响应最终导致了ANR?为了排查这种情况,我们就需要获取ANR发生时候的CPU状态参数。
1、接下来我们来看一个ANR模拟日志案例
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: ANR in com.xxxx.moblie (com.xxxx.moblie/.ui.MainActivity) (关键字ANR in + 进程名 + Activity名称)
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: PID: 1480 (进程pid)
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: Reason: Input dispatching timed out (AppWindowToken{da8f666 token=Token{5501f51 ActivityRecord{15c5c78 u0 com.xxxx.moblie/.ui.MainActivity t3862}}}, Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)(ANR的原因,输入分发超时)
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: Load: 0.0 / 0.0 / 0.0 (Load表明是1分钟,5分钟,15分钟CPU的负载)
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: CPU usage from 20ms to 20286ms later (2018-07-20 15:36:36.170 to 2018-07-20 15:36:56.436):
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 42% 6774/pressure: 41% user + 1.4% kernel / faults: 168 minor
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 34% 142/kswapd0: 0% user + 34% kernel
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 31% 1520/system_server: 13% user + 18% kernel / faults: 58724 minor 1585 major
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 13% 29901/com.ss.android.article.news: 7.7% user + 6% kernel / faults: 56007 minor 2446 major
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 13% 32638/com.android.quicksearchbox: 9.4% user + 3.8% kernel / faults: 48999 minor 1540 major
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 11% (CPU的使用率)1480/com.xxxx.moblie: 5.2%(用户态的使用率) user + (内核态的使用率) 6.3% kernel / faults: 76401 minor 2422 major
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 8.2% 21000/kworker/u16:12: 0% user + 8.2% kernel
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 0.8% 724/mtd: 0% user + 0.8% kernel / faults: 1561 minor 9 major
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 8% 29704/kworker/u16:8: 0% user + 8% kernel
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 7.9% 24391/kworker/u16:18: 0% user + 7.9% kernel
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 7.1% 30656/kworker/u16:14: 0% user + 7.1% kernel
07-20 15:36:58.711 1000 1520 1597 E ActivityManager: 7.1% 9998/kworker/u16:4: 0% user + 7.1% kernel
通过上面所提供的案例我们可以分析出以下几点:
- ANR发生的位置是:com.xxxx.moblie/.ui.MainActivity
- com.xxxx.moblie 占用了11%的CPU,CPU的使用率并不是很高,基本可以排除CPU负载的原因
- Reason提示我们是输入分发超时导致的ANR
2、下面所提供的是一个ANR的真实日志案例
10-09 19:35:22.124 940 968 E ActivityManager: ANR in com.example.anrtest (com.example.anrtest/.MainActivity) // 记录ANR+进程名+Activity名称
10-09 19:35:22.124 940 968 E ActivityManager: PID: 8390 //记录进程ID
10-09 19:35:22.124 940 968 E ActivityManager: Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 28. Wait queue head age: 5517.5ms.)(ANR的原因,输入分发超时)
10-09 19:35:22.124 940 968 E ActivityManager: Load: 2.52 / 2.57 / 2.73
10-09 19:35:22.124 940 968 E ActivityManager: CPU usage from 99984ms to 0ms ago (2022-10-09 19:33:39.209 to 2022-10-09 19:35:19.194):
10-09 19:35:22.124 940 968 E ActivityManager: 25% 445/surfaceflinger: 14% user + 11% kernel / faults: 11962 minor
10-09 19:35:22.124 940 968 E ActivityManager: 11% 394/android.hardware.graphics.composer@2.2-service: 2.9% user + 8.2% kernel / faults: 1 minor
10-09 19:35:22.124 940 968 E ActivityManager: 10% 2101/com.leapmotor.appcenter: 7.8% user + 3.1% kernel / faults: 926 minor
10-09 19:35:22.124 940 968 E ActivityManager: 3.2% 1961/com.iflytek.cutefly.speechclient.hmi: 2.5% user + 0.7% kernel / faults: 2111 minor
10-09 19:35:22.124 940 968 E ActivityManager: 1.8% 386/android.hardware.audio@2.0-service: 0.2% user + 1.6% kernel10-09 19:35:22.124 940 968 E ActivityManager: 0.9% 940/system_server: 0.6% user + 0.3% kernel / faults: 5334 minor10-09 19:35:22.124 940 968 E ActivityManager: 0.7% 440/audioserver: 0.3% user + 0.3% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.3% 277/apr_vm_cb_threa: 0% user + 0.3% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.3% 544/leap_uhab: 0% user + 0.2% kernel / faults: 20 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.3% 5219/com.leapmotor.leapmotorsoscall: 0.1% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.2% 2367/com.leapmotor.multimedia: 0% user + 0.2% kernel / faults: 9 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.2% 8215/kworker/2:3: 0% user + 0.2% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.2% 3992/adbd: 0% user + 0.2% kernel / faults: 46652 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.2% 7786/com.ebanma.tinyapp: 0.2% user + 0% kernel / faults: 557 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.2% 7895/com.ebanma.tinyapp:DataCenterService: 0.2% user + 0% kernel / faults: 463 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 543/leap_systemsdk_service: 0% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 1392/com.leapmotor.cameraaround: 0% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 410/leap_vsomeip_route: 0.1% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 3554/com.leapmotor.driverecord:emergency: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 411/leap_camera_around: 0% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 2915/com.leapmotor.systemupdate: 0% user + 0% kernel / faults: 5 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 9/rcu_preempt: 0% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 412/leap_camera_face: 0% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 413/leap_camera_front: 0% user + 0.1% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 2021/com.leapmotor.facevideo: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 2554/com.leapmotor.phone: 0% user + 0.1% kernel / faults: 10 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 1916/com.leapmotor.log: 0% user + 0% kernel / faults: 2 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 2188/com.leapmotor.camera:front_encode: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 2211/com.leapmotor.camera:around_encode: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0.1% 3541/com.leapmotor.driverecord:trip: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 285/logd: 0% user + 0% kernel / faults: 3 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 325/ais_v4l2_proxy: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 541/leap_shutdown: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 2243/com.leapmotor.camera:front_push_encode: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 1199/com.android.systemui: 0% user + 0% kernel / faults: 576 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 3492/com.leapmotor.driverecord: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 251/vlog: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 560/installd: 0% user + 0% kernel / faults: 8 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 4106/kworker/u8:0: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 6191/installer: 0% user + 0% kernel / faults: 295 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 8/ksoftirqd/0: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 18/ksoftirqd/1: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 1131/com.android.car: 0% user + 0% kernel / faults: 553 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 2134/com.leapmotor.bt:bt_service: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 7818/kworker/u9:0: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 24/ksoftirqd/2: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 512/leap_logcat: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 10/rcu_sched: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 30/ksoftirqd/3: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 70/system: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 240/kworker/u8:10: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 281/jbd2/vdb-8: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 286/servicemanager: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 287/hwservicemanager: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 330/zygote64: 0% user + 0% kernel / faults: 153 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 409/vendor.qti.hardware.perf@1.0-service: 0% user + 0% kernel / faults: 37 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 542/leap_vsomeip_qnx_heart: 0% user + 0% kernel / faults: 3 minor10-09 19:35:22.124 940 968 E ActivityManager: 0% 654/msm_irqbalance: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 677/ipacm: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 1366/.dataservices: 0% user + 0% kernel / faults: 3 minor
10-09 19:35:22.124 940 968 E ActivityManager: 0% 2665/dmesg: 0% user + 0% kernel
10-09 19:35:22.124 940 968 E ActivityManager: 0% 2893/android.process.acore: 0% user + 0% kernel / faults: 35 minor
10-09 19:35:22.124 2101 2120 I motor.appcente: Wrote stack traces to '[tombstoned]'
10-09 19:35:22.125 940 969 W ActivityManager: Force finishing activity com.example.anrtest/.MainActivity
10-09 19:35:22.127 940 969 I ActivityManager: saveTopActivity mTmpTop=com.example.anrtest/com.example.anrtest.MainActivity
通过上面所提供的案例我们可以分析出以下几点:
- ANR发生的位置是:com.example.anrtest/.MainActivity
- CPU的使用率都不是很高,基本可以排除CPU负载的原因
- Reason提示我们是输入分发超时导致的ANR
通过上面几点我们虽然排除了CPU过度负载的可能,但我们并不能准确定位出ANR的确切位置,要想准确定位出ANR发生的确切位置,就要借助系统为了解决ANR问题而提供的终极大杀器——traces.txt文件了。
3.3 traces.txt 文件分析
当APP不响应、响应慢了、或者WatchDog的监视没有得到回应时,系统就会dump出一个traces.txt文件,存放在文件目录:/data/anr/文件夹中,通过traces文件,我们可以拿到线程名、堆栈信息、线程当前状态、binder call等信息。
我们可以通过adb命令获取到该文件夹下面的所有traces文件:adb pull /data/anr
trace:
Cmd line:com.xxxx.moblie"main" prio=5 tid=1 Runnable| group="main" sCount=0 dsCount=0 obj=0x73bcc7d0 self=0x7f20814c00| sysTid=20176 nice=-10 cgrp=default sched=0/0 handle=0x7f251349b0| state=R schedstat=( 0 0 0 ) utm=12 stm=3 core=5 HZ=100| stack=0x7fdb75e000-0x7fdb760000 stackSize=8MB| held mutexes= "mutator lock"(shared held)// java 堆栈调用信息,可以查看调用的关系,定位到具体位置at ttt.push.InterceptorProxy.addMiuiApplication(InterceptorProxy.java:77)at ttt.push.InterceptorProxy.create(InterceptorProxy.java:59)at android.app.Activity.onCreate(Activity.java:1041)at miui.app.Activity.onCreate(SourceFile:47)at com.xxxx.moblie.ui.b.onCreate(SourceFile:172)at com.xxxx.moblie.ui.MainActivity.onCreate(SourceFile:68)at android.app.Activity.performCreate(Activity.java:7050)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2807)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2929)at android.app.ActivityThread.-wrap11(ActivityThread.java:-1)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1618)at android.os.Handler.dispatchMessage(Handler.java:105)at android.os.Looper.loop(Looper.java:171)at android.app.ActivityThread.main(ActivityThread.java:6699)at java.lang.reflect.Method.invoke(Native method)at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:246)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
这里详细解析一下traces.txt里面的一些字段,看看它到底能给我们提供什么信息.
- main:main标识是主线程,如果是线程,那么命名成“Thread-X”的格式,x表示线程id,逐步递增。
- prio:线程优先级,默认是5
- tid:tid不是线程的id,是线程唯一标识ID
- group:是线程组名称
- sCount:该线程被挂起的次数
- dsCount:是线程被调试器挂起的次数
- obj:对象地址
- self:该线程Native的地址
- sysTid:是线程号(主线程的线程号和进程号相同)
- nice:是线程的调度优先级
- sched:分别标志了线程的调度策略和优先级
- cgrp:调度归属组
- handle:线程处理函数的地址。
- state:是调度状态
- schedstat:从 /proc/[pid]/task/[tid]/schedstat读出,三个值分别表示线程在cpu上执行的时间、线程的等待时间和线程执行的时间片长度,不支持这项信息的三个值都是0;
- utm:是线程用户态下使用的时间值(单位是jiffies)
- stm:是内核态下的调度时间值
- core:是最后执行这个线程的cpu核的序号。
- 参数详细信息见ANR-Java进程的Trace文件解析
Java的堆栈信息是我们最关心的,它能够定位到具体位置。从上面的traces,我们可以判断ttt.push.InterceptorProxy.addMiuiApplicationInterceptorProxy.java:77 导致了com.xxxx.moblie发生了ANR。这时候可以对着源码查看,找到出问题,并且解决它。
接下来再看一个真实的导致ANR的trace案例:
//开头显示进程号、ANR发生的时间点和进程名称
----- pid 4972 at 2022-10-09 16:45:41 -----
Cmd line: com.example.anrtest...省略...DALVIK THREADS (14)://以下是各个线程的函数堆栈信息//依次是:线程名(后面标识有daemon说明是个守护线程)、线程优先级、线程号、线程当前状态(TIMED_WAIT或SUSPENDED在anr时很常见)
"Signal Catcher" daemon prio=5 tid=3 Runnable
//依次是:线程组名称、suspendCount个数、debugSuspendCount个数、标记,线程的Java对象地址、线程的Native对象地址| group="system" sCount=0 dsCount=0 flags=0 obj=0x15980100 self=0x7322e16400//sysTid是线程号,主线程的线程号和进程号相同| sysTid=4978 nice=0 cgrp=default sched=0/0 handle=0x731c3304f0| state=R schedstat=( 5583230 6778645 10 ) utm=0 stm=0 core=3 HZ=100| stack=0x731c235000-0x731c237000 stackSize=1009KB| held mutexes= "mutator lock"(shared held)
//“Signal Catcher”负责接收和处理kernel发送的各种信号,例如SIGNAL_QUIT、SIGNAL_USR1等就是被该线程
//接收到,这个文件的内容就是由该线程负责输出的,可以看到它的状态是RUNNABLE,不过此线程也不需要关心...省略...//主线程,当前处于休眠状态
"main" prio=5 tid=1 Sleeping| group="main" sCount=1 dsCount=0 flags=1 obj=0x73e64b08 self=0x7322e14c00| sysTid=4972 nice=-10 cgrp=default sched=0/0 handle=0x73a88cc548| state=S schedstat=( 618097798 184039398 700 ) utm=56 stm=5 core=3 HZ=100| stack=0x7fd05f2000-0x7fd05f4000 stackSize=8MB| held mutexes=at java.lang.Thread.sleep(Native method)- sleeping on <0x0d9c45cc> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:373)- locked <0x0d9c45cc> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:314)at android.os.SystemClock.sleep(SystemClock.java:127)at com.example.anrtest.MainActivity$1.onClick(MainActivity.java:57)at android.view.View.performClick(View.java:6597)at android.view.View.performClickInternal(View.java:6574)at android.view.View.access$3100(View.java:778)at android.view.View$PerformClick.run(View.java:25885)at android.os.Handler.handleCallback(Handler.java:873)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:193)at android.app.ActivityThread.main(ActivityThread.java:6718)at java.lang.reflect.Method.invoke(Native method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)...省略..."Jit thread pool worker thread 0" daemon prio=5 tid=2 Native| group="main" sCount=1 dsCount=0 flags=1 obj=0x15980000 self=0x731c029000| sysTid=4977 nice=9 cgrp=default sched=0/0 handle=0x731c4314f0| state=S schedstat=( 122669387 79479997 188 ) utm=8 stm=3 core=3 HZ=100| stack=0x731c333000-0x731c335000 stackSize=1021KB| held mutexes=...省略...//Binder线程是进程的线程池中用来处理binder请求的线程
"Binder:4972_1" prio=5 tid=9 Native| group="main" sCount=1 dsCount=0 flags=1 obj=0x159829a0 self=0x731a60d000| sysTid=4984 nice=0 cgrp=default sched=0/0 handle=0x73099b34f0| state=S schedstat=( 12586983 41079166 22 ) utm=1 stm=0 core=3 HZ=100| stack=0x73098b8000-0x73098ba000 stackSize=1009KB| held mutexes=...省略...
四 ANR分析流程总结
总结一下上面我们分析ANR的主体流程:
1、首先我们搜索am_anr,找到出现ANR的时间点、进程PID、ANR类型、然后再找搜索PID,找前5秒左右的日志。
2、过滤ANR IN 查看CPU信息
3、接着查看traces.txt,找到java的堆栈信息定位代码位置,最后查看源码,分析与解决问题。
到这里,通过上面三个步骤我们基本就能定位出来大部分ANR的来龙去脉了。
我在接下来还继续提供了多个ANR案例供大家参考分析,有兴趣的可以看着。
五 ANR 案例整理
1、主线程被其他线程lock,导致死锁
waiting on <0x1cd570> (a android.os.MessageQueue)
DALVIK THREADS:
"main" prio=5 tid=3 TIMED_WAIT| group="main" sCount=1 dsCount=0 s=0 obj=0x400143a8| sysTid=691 nice=0 sched=0/0 handle=-1091117924at java.lang.Object.wait(Native Method)- waiting on <0x1cd570> (a android.os.MessageQueue)at java.lang.Object.wait(Object.java:195)at android.os.MessageQueue.next(MessageQueue.java:144)at android.os.Looper.loop(Looper.java:110)at android.app.ActivityThread.main(ActivityThread.java:3742)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:515)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)at dalvik.system.NativeStart.main(Native Method)"Binder Thread #3" prio=5 tid=15 NATIVE| group="main" sCount=1 dsCount=0 s=0 obj=0x434e7758| sysTid=734 nice=0 sched=0/0 handle=1733632at dalvik.system.NativeStart.run(Native Method)"Binder Thread #2" prio=5 tid=13 NATIVE| group="main" sCount=1 dsCount=0 s=0 obj=0x1cd570| sysTid=696 nice=0 sched=0/0 handle=1369840at dalvik.system.NativeStart.run(Native Method)"Binder Thread #1" prio=5 tid=11 NATIVE| group="main" sCount=1 dsCount=0 s=0 obj=0x433aca10| sysTid=695 nice=0 sched=0/0 handle=1367448at dalvik.system.NativeStart.run(Native Method)----- end 691 -----
2、主线程做耗时的操作:比如数据库读写。
"main" prio=5 tid=1 Native
held mutexes=
kernel: (couldn't read /proc/self/task/11003/stack)
native: #00 pc 000492a4 /system/lib/libc.so (nanosleep+12)
native: #01 pc 0002dc21 /system/lib/libc.so (usleep+52)
native: #02 pc 00009cab /system/lib/libsqlite.so (???)
native: #03 pc 00011119 /system/lib/libsqlite.so (???)
native: #04 pc 00016455 /system/lib/libsqlite.so (???)
native: #16 pc 0000fa29 /system/lib/libsqlite.so (???)
native: #17 pc 0000fad7 /system/lib/libsqlite.so (sqlite3_prepare16_v2+14)
native: #18 pc 0007f671 /system/lib/libandroid_runtime.so (???)
native: #19 pc 002b4721 /system/framework/arm/boot-framework.oat (Java_android_database_sqlite_SQLiteConnection_nativePrepareStatement__JLjava_lang_String_2+116)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
locked <0x0db193bf> (a java.lang.Object)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:690)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:299)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
locked <0x045a4a8c> (a com.xxxx.video.common.data.DataBaseHelper)
at com.xxxx.video.common.data.DataBaseORM.<init>(DataBaseORM.java:46)
at com.xxxx.video.common.data.DataBaseORM.getInstance(DataBaseORM.java:53)
locked <0x017095d5> (a java.lang.Class<com.xxxx.video.common.data.DataBaseORM>)
3、binder数据量过大
07-21 04:43:21.573 1000 1488 12756 E Binder : Unreasonably large binder reply buffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling 1 size 388568 (data: 1, 32, 7274595)
07-21 04:43:21.573 1000 1488 12756 E Binder : android.util.Log$TerribleFailure: Unreasonably large binder reply buffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling 1 size 388568 (data: 1, 32, 7274595)
07-21 04:43:21.607 1000 1488 2951 E Binder : Unreasonably large binder reply buffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling 1 size 211848 (data: 1, 23, 7274595)
07-21 04:43:21.607 1000 1488 2951 E Binder : android.util.Log$TerribleFailure: Unreasonably large binder reply buffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling 1 size 211848 (data: 1, 23, 7274595)
07-21 04:43:21.662 1000 1488 6258 E Binder : Unreasonably large binder reply buffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling 1 size 259300 (data: 1, 33, 7274595)
4、binder 通信失败
07-21 06:04:35.580 <6>[32837.690321] binder: 1698:2362 transaction failed 29189/-3, size 100-0 line 3042
07-21 06:04:35.594 <6>[32837.704042] binder: 1765:4071 transaction failed 29189/-3, size 76-0 line 3042
07-21 06:04:35.899 <6>[32838.009132] binder: 1765:4067 transaction failed 29189/-3, size 224-8 line 3042
07-21 06:04:36.018 <6>[32838.128903] binder: 1765:2397 transaction failed 29189/-22, size 348-0 line 2916
六 模拟触发ANR事件,获取trace文件
以下的几个案例,都是我通过代码故意触发ANR所产生的trace文件。
1、输入的事件在5秒内没有被响应,主线程被阻塞。
输入事件5s没有响应,如onClick事件。这是anr问题的主要类型,一般开发者不会犯这样的错,凡是耗时的操作都另开线程处理,如果疏忽了看看自己的代码就知道怎么处理。
(1)模拟触发ANR:
findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {SystemClock.sleep(40000);//故意响应超时导致ANR}});
(2)对应的Trace文件关键日志:
DALVIK THREADS (14): //虚拟机线程被阻塞
"Signal Catcher" daemon prio=5 tid=3 Runnable| group="system" sCount=0 dsCount=0 flags=0 obj=0x15980100 self=0x7322e16400| sysTid=4978 nice=0 cgrp=default sched=0/0 handle=0x731c3304f0| state=R schedstat=( 5583230 6778645 10 ) utm=0 stm=0 core=3 HZ=100| stack=0x731c235000-0x731c237000 stackSize=1009KB| held mutexes= "mutator lock"(shared held)"main" prio=5 tid=1 Sleeping //主线程被阻塞| group="main" sCount=1 dsCount=0 flags=1 obj=0x73e64b08 self=0x7322e14c00| sysTid=4972 nice=-10 cgrp=default sched=0/0 handle=0x73a88cc548| state=S schedstat=( 618097798 184039398 700 ) utm=56 stm=5 core=3 HZ=100| stack=0x7fd05f2000-0x7fd05f4000 stackSize=8MB| held mutexes=at java.lang.Thread.sleep(Native method)- sleeping on <0x0d9c45cc> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:373)- locked <0x0d9c45cc> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:314)at android.os.SystemClock.sleep(SystemClock.java:127) //代码被阻塞的关键位置at com.example.anrtest.MainActivity$1.onClick(MainActivity.java:57) //按钮的点击事件at android.view.View.performClick(View.java:6597)at android.view.View.performClickInternal(View.java:6574)at android.view.View.access$3100(View.java:778)at android.view.View$PerformClick.run(View.java:25885)at android.os.Handler.handleCallback(Handler.java:873)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:193)at android.app.ActivityThread.main(ActivityThread.java:6718)at java.lang.reflect.Method.invoke(Native method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2、广播接收者的onReceive方法在10秒内没有执行完毕。
BroadcastReceiver是在程序主线程运行,而且默认情况下BroadcastReceiver的运行时间为10s,所以不能有耗时操作,如果耗时超过10s就会导致anr,从traces文件log就可以看出onReceive不能进行耗时任务。
(1)模拟触发ANR:
IntentFilter intentFilter = new IntentFilter();intentFilter.addAction("com.anr.test");registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {SystemClock.sleep(40000);//故意响应超时导致ANR}}, intentFilter);
(2)对应的Trace文件关键日志:
DALVIK THREADS (14): //虚拟机线程被阻塞
"Signal Catcher" daemon prio=5 tid=3 Runnable| group="system" sCount=0 dsCount=0 flags=0 obj=0x13100088 self=0x7322e16400| sysTid=6639 nice=0 cgrp=default sched=0/0 handle=0x731c3304f0| state=R schedstat=( 6547603 5577708 11 ) utm=0 stm=0 core=0 HZ=100| stack=0x731c235000-0x731c237000 stackSize=1009KB| held mutexes= "mutator lock"(shared held)"main" prio=5 tid=1 Sleeping //主线程被阻塞| group="main" sCount=1 dsCount=0 flags=1 obj=0x73e64b08 self=0x7322e14c00| sysTid=6633 nice=-10 cgrp=default sched=0/0 handle=0x73a88cc548| state=S schedstat=( 605006551 138044643 533 ) utm=56 stm=3 core=2 HZ=100| stack=0x7fd05f2000-0x7fd05f4000 stackSize=8MB| held mutexes=at java.lang.Thread.sleep(Native method)- sleeping on <0x08c05759> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:373)- locked <0x08c05759> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:314)at android.os.SystemClock.sleep(SystemClock.java:127) //代码被阻塞的关键位置at com.example.anrtest.MainActivity$3.onReceive(MainActivity.java:80) //广播接收者的onReceive方法at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1391)at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(lambda:-1)at android.os.Handler.handleCallback(Handler.java:873)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:193)at android.app.ActivityThread.main(ActivityThread.java:6718)at java.lang.reflect.Method.invoke(Native method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
BroadcastReceiver是Android的消息组件,用来组件之间、应用之间的消息传递,生命周期太短也不能开子线程处理耗时任务,耗时任务一般转交给IntentService或者JobIntentService去做。
3、服务Service没有及时响应
Service是计算型组件,虽然在后台运行,但是本质上它也跑在主线程,如果你的服务要做任何CPU密集型(如MP3播放)或阻塞(如网络)操作,都要放在子线程中,否则耗时超过20s就会导致anr。下面我在onStartCommand方法中休眠40秒。
(1)模拟触发ANR:
@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {SystemClock.sleep(40000);//故意响应超时导致ANRreturn super.onStartCommand(intent, flags, startId);}
(2)对应的Trace文件关键日志:
DALVIK THREADS (13): //虚拟机线程被阻塞
"Signal Catcher" daemon prio=5 tid=3 Runnable| group="system" sCount=0 dsCount=0 flags=0 obj=0x13940108 self=0x7322e16400| sysTid=7658 nice=0 cgrp=default sched=0/0 handle=0x731c3304f0| state=R schedstat=( 5995782 10695989 10 ) utm=0 stm=0 core=3 HZ=100| stack=0x731c235000-0x731c237000 stackSize=1009KB| held mutexes= "mutator lock"(shared held)"main" prio=5 tid=1 Sleeping //主线程被阻塞| group="main" sCount=1 dsCount=0 flags=1 obj=0x73e64b08 self=0x7322e14c00| sysTid=7652 nice=-10 cgrp=default sched=0/0 handle=0x73a88cc548| state=S schedstat=( 595004855 101962599 596 ) utm=40 stm=18 core=2 HZ=100| stack=0x7fd05f2000-0x7fd05f4000 stackSize=8MB| held mutexes=at java.lang.Thread.sleep(Native method)- sleeping on <0x0e096f2a> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:373)- locked <0x0e096f2a> (a java.lang.Object)at java.lang.Thread.sleep(Thread.java:314)at android.os.SystemClock.sleep(SystemClock.java:127) //代码被阻塞的关键位置at com.example.anrtest.ANRService.onStartCommand(ANRService.java:17) //服务的onStartCommand方法at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3705)at android.app.ActivityThread.access$1600(ActivityThread.java:200)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1688)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loop(Looper.java:193)at android.app.ActivityThread.main(ActivityThread.java:6718)at java.lang.reflect.Method.invoke(Native method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
相关文章:
Android中ANR的分析和解决
一 ANR概述 2、ANR的类型 (1)KeyDispatchTimeout(常见) input事件在5S内没有处理完成发生了ANR。 logcat日志关键字:Input event dispatching timed out (2)BroadcastTimeout 前台Broadcast…...
Kotlin 类
文章目录 什么是类类的属性类的方法(行为)构造函数主构造次构造 类的实例化(对象)伴生对象this 什么是类 在 Kotlin 中,变量类型都是类,像我们常见的Int、String等等,都是类。 为什么要分类&a…...
Forth Python语言:深度解析其四维、五维、六维与七维之奥秘
Forth Python语言:深度解析其四维、五维、六维与七维之奥秘 在编程语言的浩瀚星空中,Forth Python以其独特的魅力与深邃的内涵,吸引着众多探索者的目光。然而,这门语言究竟有何独到之处?本文将从四维、五维、六维和七…...

MySQL--复合查询
之前学过了基本的查询,虽然已经够80%的使用场景了,但是依旧需要了解剩下的20%。 一、多表笛卡尔积(多表查询) 以前我们使用基本查询的时候,from后面就跟一张表名,在多表查询这里,from后面可以跟…...

前端项目开发,3个HTTP请求工具
这一小节,我们介绍一下前端项目开发中,HTTP请求会用到的3个工具,分别是fetch、axios和js-tool-big-box中的jsonp请求。那么他们都有哪些小区别呢?我们一起来看一下。 目录 1 fetch 2 axios 3 js-tool-big-box 的 jsonp 请求 …...

Java_Mybatis
Mybatis是一款优秀的持久层框架,用户简化JDBC(使用Java语言操作关系型数据库的一套API)开发 使用Mybatis查询所有用户数据: 代码演示: UserMapper: Mapper //被调用时会通过动态代理自动创建实体类,并放入IOC容器中…...

2024HW|常见红队使用工具
目录 什么是HW? 什么是网络安全红蓝对抗? 红队 常见工具 信息收集工具 Nmap 简介 漏洞扫描工具 Nessus简介 AWVS 简介 抓包工具 Wireshark简介 TangGo 简介 web 应用安全工具 Burpsuite 简介 SQLMap webshell 管理工具 蚁剑 冰蝎 后…...

Redisson集成SpringBoot
前言:Redisson集成SpringBoot主要有两种方式,一个是使用redisson-spring-boot-starter依赖(优先推荐),毕竟springboot主打的就是约定大于配置,这个依赖就是为springboot准备的。 再一种方式就是引入rediss…...

设计模式(十二)行为型模式---模板方法模式
文章目录 模板方法模式结构优缺点UML图具体实现UML图代码实现 模板方法模式 模板方法模式(Template Method)是一种基于继承实现的设计模式,主要思想是:将定义的算法抽象成一组步骤,在抽象类中定义算法的骨架ÿ…...

【气象常用】剖面图
效果图: 主要步骤: 1. 数据准备:我用的era5的散度数据(大家替换为自己的就好啦,era5数据下载方法可以看这里【数据下载】ERA5 各高度层月平均数据下载_era5月平均数据-CSDN博客) 2. 数据处理:…...

LabVIEW高低温试验箱控制系统
要实现LabVIEW高低温试验箱控制系统,需要进行硬件配置、软件设计和系统集成,确保LabVIEW能够有效地监控和控制试验箱的温度。以下是详细说明: 硬件配置 选择合适的试验箱: 确定高低温试验箱的型号和品牌。 确认试验箱是否支持外…...
Flutter 中的 SliverFillViewport 小部件:全面指南
Flutter 中的 SliverFillViewport 小部件:全面指南 Flutter 是一个由 Google 开发的跨平台 UI 框架,它允许开发者使用 Dart 语言来构建高性能、美观的移动、Web 和桌面应用。在 Flutter 的丰富组件库中,SliverFillViewport 是一个用于 Custo…...

明日周刊-第12期
以前小时候最期待六一儿童节了,父母总会给你满足一个愿望,也许是一件礼物也许是一次陪伴。然而这个世界上其实还有很多儿童过不上儿童节,比如某些地区的小孩子,他们更担心的是能不能见到明天的太阳。 文章目录 一周热点航天探索火…...
算法之美阅读笔记
这里写自定义目录标题 序04 缓存 -- 忘了它吧 序 在图书馆闲逛时,一本封面为绿色的清新的书引起了我的兴趣,书名是算法之美。我心里不禁嘀咕,大家好喜欢使用某某之美作为书名,比如:数学之美、架构之美。美丽美好的事物…...
新手学习STM32还是ESP32
对于新手来说,选择学习STM32还是ESP32取决于个人的学习目标和背景。以下是针对这两种微控制器的详细分析,以便您做出更明智的选择: STM32 1. 处理器架构与性能 STM32采用单核或多核处理器架构,基于ARM Cortex-M0,M0…...

关于vlookup的第一个参数的个人理解
VLOOKUP(查阅值,包含查阅值和返回值的查找区域,查找区域中返回值的列号,精确查找或近似查找) 我个人理解,第一个参数应该叫线索值,因为我们要通过它去找与其对应的(也就是与其同行的…...

vector实现后半部分
一.迭代器失效 1.定义 指原迭代器在扩容/缩容/修改后指向无效元素或无效地址处 erase的迭代器失效 2.原因: 1.有的编译器实现erase会缩容拷贝 2.删除最后一个后,其指向无效元素 VS中不允许再次使用erase完的迭代器,为了让编写的代码移植…...

Maven配置
Maven – Download Apache Maven https://maven.apache.org/install.html 得下载有 bin的...
python 第一天
循环打印 while循环 languages ["Regional Assembly Language","Autocode","FORTRAN","IPL (LISP的先驱)","FLOW-MATIC (COBOL的先驱)","COMTRAN (COBOL的先驱)","LISP","ALGOL 58","F…...

Day03 左侧菜单数据绑定
一.左侧菜单数据绑定 1.首先,进行项目结构塔建。按照Prism 框架约定,要使用自动查找绑定功能。即View (视图)中自动查找并绑定到对应的ViewModel(视图模型,处理视图业务逻辑)。就需要在项目中按…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...