当前位置: 首页 > news >正文

Android 性能优化——ANR监控与解决

作者:Drummor

1 哪来的ANR

ANR(Application Not responding):如果 Android 应用的界面线程处于阻塞状态的时间过长,会触发“应用无响应”(ANR) 错误。如果应用位于前台,系统会向用户显示一个对话框。ANR 对话框会为用户提供强制退出应用的选项。

ANR 是一个问题,因为负责更新界面的应用主线程无法处理用户输入事件或绘制操作,这会引起用户的不满

以上是官方对ANR的描述,ANR的目的是从系统层面对严重影响用户直接感知的输入和界面绘制操作的行为进行的一种自我保护。

1.1 四种条件

在系统层面触发ANR的就只有四个节点。也就是说即时主线程有一个很长的耗时任务,如果没有触发ANR产生的条件也不会产生ANR。

出现以下任何情况时,系统都会针对您的应用触发 ANR:

  • 输入调度的超时,阈值为5秒
  • Service执行超时,无法在阈值内完成服务的创建和启动也会触发ANR,前台任务的阈值为10s后台任务的阈值为60s
  • ContentProvider调度超时,这个阈值为10s
  • BroadcastReceiver 调度超时,这个阈值为10s

1.2 系统产生ANR大概流程

以BroadcastReceive超时为例,看下系统如何触发ANR

1.2.1 BroadcastReceiver 产生ANR

BroadcastReceiver处理广播的核心逻辑位于BroadcastQueue

public final class BroadcastQueue {final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {setBroadcastTimeoutLocked(timeoutTime);...performReceiveLocked(...);//内部最终会调用BroadcastReceiver的onReceiver...cancelBroadcastTimeoutLocked();//解除超时..}// 设置超时final void setBroadcastTimeoutLocked(long timeoutTime) {if (!mPendingBroadcastTimeoutMessage) {Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);mHandler.sendMessageAtTime(msg, timeoutTime);mPendingBroadcastTimeoutMessage = true;}}//解除超时final void cancelBroadcastTimeoutLocked() {if (mPendingBroadcastTimeoutMessage) {mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);mPendingBroadcastTimeoutMessage = false;}
}

以上是广播结束者设置、解除、触发ANR的核心逻辑。通过handler机制延迟发送一个【ANR 任务】,在规定时间内完成了你广播接收者任务移除ANR任务。否则触发。

1.2.1 系统处理ANR

实际无论何种条件触发了ANR最终都交给AnrHelper处理,这个类中核心处理ANR的逻辑开启一个名为“AnrConsumer”的线程。执行在ProcessErrorStateRecord中appNotResponding()的方法。

 void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,String parentShortComponentName, WindowProcessController parentProcess,boolean aboveSystem, String annotation, boolean onlyDumpSelf) {ArrayList<Integer> firstPids = new ArrayList<>(5);SparseArray<Boolean> lastPids = new SparseArray<>(20);...setNotResponding(true);//标记ANR标识...firstPids.add(pid);...isSilentAnr = isSilentAnr();//后台的应用发生ANRif (!isSilentAnr && !onlyDumpSelf) {//前台进程和不仅仅dump自身时mService.mProcessList.forEachLruProcessesLOSP(false, r -> {...firstPids.add(pid);//添加其他进程}}); ...StringBuilder report = new StringBuilder();report.append(MemoryPressureUtil.currentPsiState());//内存信息ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);//cup信息nativePids.add(..); //添加native进程...File tracesFile =  .. report.append(tracesFileException.getBuffer());info.append(processCpuTracker.printCurrentState(anrTime));
​if (tracesFile == null) {Process.sendSignal(pid, Process.SIGNAL_QUIT); //不dump信息时直接发送SIGNAL_QUIT信号}...File tracesFile = ActivityManagerService.dumpStackTraces(..); //dump栈...mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);//ANR弹窗}

值得注意的点

  • 沉默的ANR”,前台ANR会弹无响应的Dialog,后台ANR会直接杀死进程**。
  • dump信息时优先dump发生ANR进程的信息,条件允许dump其他关联进程和native进程。如果系统进程有很多ANR需要处理,且耗时已经超过60s或者是沉默进程就只会dump发生ANR进程信息
  • dump全部进程的总时间不能超过20秒,如果超过了,马上返回,确保ANR弹窗可以及时的弹出(或者被kill掉)
  • Process.sendSignal(pid, Process.SIGNAL_QUIT);系统会发出Process.SIGNAL_QUIT信号。这个很重要

(图来自微信团队)

当应用发生ANR之后,系统会收集许多进程,来dump堆栈,从而生成ANR Trace文件,收集的第一个,也是一定会被收集到的进程,就是发生ANR的进程,接着系统开始向这些应用进程发送SIGQUIT信号,应用进程收到SIGQUIT后开始dump堆栈。

2 应用层怎么监控

Android M(6.0) 版本之后,应用侧不能直接通过监听 data/anr/trace 文件,监控是否发生 ANR。

2.1 WatchDog方案

该方案我们在卡顿监控文章里也介绍过,主要思路就是超时检测,检测主线程MessageQueue在规定时间(5s)内是否处理了给定的消息。如果规定时间内没有处理掉给定的消息就认为发生了ANR。

该方案用于检测ANR的弊端:

  • 不准确:该方案触发了超时条件不一定会产生ANR。5秒超时只是ToucEvent 未被消费发生ANR的条件。其他的产生ANR的条件的并不是5s;
  • 不优雅:该方案会一直让主线程消息调度一直处于“繁忙状态”,对应用功耗和负载有不必要的影响。

2.2 监听信号方案(SIGQUIT

系统发生ANR的时候,发出SIGQUIT信号,通过监听这一信号,我们可以判断ANR的发生。该方案也是市面上监听ANR的主要方案。

除Zygote进程外,每个进程有SignalCatcher线程,捕获SIGQUIT信号然后做相应的动作。Android默认把SIGQUIT设置为BLOCKED,这意味着只能只有SignalCatcher线程能监听到SIGQUIT信号,我们注册sigaction监听不到。我们把SIGQUIT设置为UNBLOCK这样就可能收到信号。但要注意,需要讲信号重新发送出去,不破坏系统的机制。

2.2.1 误报 & 完善

系统发出SIGQUIT 信号不一定该应用发生了ANR,其他情况下也会发出’SIGQUIT’信号,比如其他进程发生了ANR

源码里找答案

    private void makeAppNotRespondingLSP(String activity, String shortMsg, String longMsg) {setNotResponding(true);// mAppErrors can be null if the AMS is constructed with injector only. This will only// happen in tests.if (mService.mAppErrors != null) {mNotRespondingReport = mService.mAppErrors.generateProcessError(mApp,ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, //把发生ANR的进程activity, shortMsg, longMsg, null);}startAppProblemLSP();mApp.getWindowProcessController().stopFreezingActivities();}

发生ANR时系统会把发生ANR的进程标记 NOT_RESPONDING,我们可以在应用层通过ActivityManager check该状态,代码乳如下:

private static boolean checkErrorState() {try {ActivityManager am = (ActivityManager) application.getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.ProcessErrorStateInfo> procs = am.getProcessesInErrorState();if (procs == null) return false;for (ActivityManager.ProcessErrorStateInfo proc : procs) {if (proc.pid != android.os.Process.myPid()) continue;if (proc.condition != ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING) continue;return true;}return false;} catch (Throwable t){}return false;
}

当收到SIGQUIT信号之后,在一个时间段内不断的check该状态,如果获取到了该标识,就可以认为当前进程发生了ANR。

2.2.2 漏报&完善

有些ANR发生不会把进程不会设置NOT_RESPONDING标识

  • 沉默ANR(SilentAnr),SilentANR 会直接kill进程,不会设置该标识。
  • 闪退ANR,OPPO VIVO 的机型ANR之后,会直接闪退,也不会设置该标识。

应对方案:结合主线程的卡顿状态。

反射获取主线程MessageQueuemMessages 对象,此对象的when变量时预期该消息被处理的时间,该变量和当前时间做差就能得到该消息等待的时间,被耽误的耗时,如果该耗过长,就说明主线程‘卡顿’了。

收到了SIGQUIT且当前主线程卡顿了,就认为发生了 ANR。

2.2.3 ANR 监控小结

通过监听系统SIGQUIT信号结合check 当前进程的 NOT_RESPONDING标识和主线程的卡顿状态,综合判定为该进程发生了ANR。

这只是我们知道发生了ANR,知道发生了ANR,进一步知道什么导致了ANR,采集ANR发生时的上下文环境信息,解决ANR更重要。

3 信息的采集监控

3.1 ANR问题定位难点

观察ANR信息采集的难点在于往往信息采集不准确、不全面,当ANR发生的当下采集的信息并不是ANR的真正诱因,因而采集的信息对排查问题的参考价值大折扣。

如上图所示,在主线程耗时的任务已经执行完毕,service启动任务在超过了规定的阈值产生了ANR,此时采集的信息是一个正常的任务调用信息。

总的来说,诱发ANR的原因分主线程执行耗时过大和系统负载过重。

主线程任务执行耗时过大又可大概分为一下几种

  • 历史消息里有多个耗时较重,触发了ANR。
  • 历史消息里有一个耗时极其重的消息。
  • 极其多个耗时小消息执行综合起来耗时严重,触发ANR。

系统负载过重,包括系统内存不足,cpu负载,导致任务得不到执行。

如果能较完整记录过完一段时间段内主线程历史消息任务、当前执任务和将要执行的任务以及系统负载情况,对我们更为准确的诊断ANR问题有非常重要的意义。

3.2 消息调度监控

主线程中记录监控Looper消息执行方案,我们自然的把目光转移到了Looper的Printer方案上。关于这个在三板斧的前两篇文章都介绍过这里不展开。

Looper分发消息执行的时候,前后都打印消息信息,我们依此可以获取到消息任务的相关信息,包活Message的targetwhatcallback、消息执行的耗时等。

消息耗时,需要采集主线程的WallTime和ThreadTime。

  • WallTime:任务占用的时间,包括等待锁,线程休眠时间片流转的时间。
  • ThreadTime(CpuTime)时线程真实执行的时间,不包括等待锁等时间。依次我们可以在侧面推断系统负载情况。

大部分情况下,消息执行都耗时较短,Looper也会有Idel状态,即无消息执行的状态,我们需要对这些消息进行聚合处理。

此外,三板斧系列文章主线程耗时监控里有介绍主线程处理消息除了Looper正常的分发的消息需要监控外,IdleHandler、TouchEvent消息也要纳入到统计记录里才更为完整。

3.2.1 消息聚合以及分类

  • 连续的耗时较小的消息聚合统计,连续小于50ms 的消息,聚合成一条记录,该记录里存储消息的数量,和总耗时信息等
  • 超过阈值的消息单做一条记录统计。
  • 系统调用消息统计(ActivityThread.H Activity 、Service、 ContentProvider),这些对我们分析ANR问题很重要。
  • IDLE状态消息单独统计。
  • IdleHandler 的统计。
  • TouchEvent 等native 层触发的主线程调度任务统计。

综合来说,把消息分类型,聚合类型(Agree),连续的耗时较少的消息。耗时类型(Huge):超过50ms的消息。系统调用消息(SYSTEM)

3.2.2 消息堆栈采集

除了,统计记录Looper Messge的what、callback和耗时之外,每个消息内到底执行了什么哪些动作也需要采集,这就需要采集每个消息的执行的栈,频繁的采集执行栈对性能影响较大,要进行有策略的采集。

  • 开启子线程采集主线程的堆栈。
  • 耗时较少的消息任务不采集。
  • 超过一定阈值还未执行完毕的消息任务进行一次采集,再隔一段时间如果本次消息任务还未执行完,再进行采集,间隔时间是依此线性增加。
  • 【shoppe的非堵塞式高效抓栈】

3.2.3 正在执行的消息和pending消息统计

除了监控 ANR 发生之前主线程历史消息调度及耗时之外,也需要知道 ANR 发生时正在调度的消息及其耗时,以便于在看到 ANR 的 Trace 堆栈时,可以清晰的知道当前 Trace 逻辑到底执行了多长时间

MessageQueue中等待执行的消息也很有必要统计

  • 对我们知道什么组件诱发了ANR的产生
  • 可以统计等待执行的消息等待了多久。判断消息队列繁忙程度。

3.3 更全面的信息采集

以上我们比较全面的监控统计主线程调度任务的耗时,

3.3.1 获取ANRInfo

应用层可通过AcivityManager获取ANRInfo

    val am = application.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManagerval processesInErrorStates = am.processesInErrorState

ProcessesInErrorState中可获取到

 shortMsg: ANR Inputdispatching timed out ...
  • shortMessage:ANR 产生的直接原因,TouchEvent超时,Servcie启动超时等。
Reason: Input dispatching timed out 
xxx is not responding. Waited 5003ms for FocusEvent(hasFocus=false))                                                                                                                                                                          
Load: 3.19 / 2.46 / 2.42
​
----- Output from /proc/pressure/memory -----
some avg10=0.00 avg60=0.00 avg300=0.00 total=144741615
full avg10=0.00 avg60=0.00 avg300=0.00 total=29370150
----- End output from /proc/pressure/memory -----CPU usage from 0ms to xxx ms later with 99% awake:
​
TOTAL: 6.4% user + 8.2% kernel + 0% iowait + 0.6% irq + 0.1% softirq
​
CPU usage from 0ms to xxx ms later with 99% awake:
​
27% TOTAL: 10% user + 14% kernel + 0.3% iowait + 0.9% irq + 0.3% softirq
  • longMessage:包括系统负载,cup使用情况,IO情况等系统情况。

3.3.2 Logcat 日志

应用运行时采集logcat日志,注意需要控制量有相应的策略,定时清理。

String cmd = "logcat -f " + file.getAbsolutePath();
Runtime.getRuntime().exec(cmd);

3.3.3 当前进程其他线程的堆栈信息

从 Java 层获取各线程堆栈,或通过反射方式获取到虚拟机内部 Dump 线程堆栈的接口,在内存映射的函数地址,强制调用该接口,并将数据重定向输出到本地。

这样当ANR发生时我们就有丰富的信息供我们参考,包括主线程过去现在和未来的调度信息,系统的信息,线程信息,Logcat信息。

4 问题分析定位和解决

4.1 分析主线程调度情况

查看我们主线程任务调度,是否有明显的耗时任务执行,诱发ANR产生。

  • 分析我们记录的消息调度的wallTime和cputime
  • 定位记录的耗时消息堆栈定位出问题
  • 注意有可能出现连续的非常多的耗时小的消息也会造成ANR

4.2 ANR Info解读

4.2.1 系统负载情况

Load: xx/xx/xx

ANR发生的前1分钟 5分钟和15分钟时间段内的CPU负载,数值代表着等待系统调度的任务数,数值过高,意味着系统有CPU和IO竞争激烈,我们的应用进程可能收到影响

4.2.2 CPU占用情况

CPU usage from 0ms to xxx ms later with xx% awake:
​
14% 1673/system_server: 8% user + 6.7% kernel / faults: 12746 minor
13% 30829/tv.danmaku.bili: 7.3% user + 6.2% kernel / faults: 24286 minor
6.6% 31147/tv.danmaku.bili:ijkservice: 3.7% user + 2.8% kernel / faults: 11880 minor
6% 574/logd: 2.1% user + 3.8% kernel / faults: 64 minor
..
TOTAL: 6.4% user + 8.2% kernel + 0% iowait + 0.6% irq + 0.1% softirq
​
CPU usage from xxms to xxxms later 
73% 1673/system_server: 49% user + 24% kernel / faults: 1695 minor33% 2330/AnrConsumer: 12% user + 21% kernel15% 1683/HeapTaskDaemon: 15% user + 0% kernel9.2% 7013/Binder:1673_12: 6.1% user + 3% kernel6.1% 1685/ReferenceQueueD: 6.1% user + 0% kernel6.1% 2715/HwBinder:1673_5: 6.1% user + 0% kernel3% 2529/PhotonicModulat: 0% user + 3% kernel
25% 30829/tv.danmaku.bili: 4.2% user + 21% kernel / faults: 423 minor25% 31050/thread_ad: 4.2% user + 21% kernel......                                                                                                   
27% TOTAL: 10% user + 14% kernel + 0.3% iowait + 0.9% irq + 0.3% softirq

如上,表示ANR发生前后的CPU占用情况,以及这些进程具体占用情况。

  • user:用户态
  • kernel:内核态
  • iowait:io等待。过高可能发生文件读写或内存紧张的情况。
  • irq:硬中断
  • softirq:软中断 占比

注意:单进程CPU的负载并不是以100%为上限,而是有几个核,就有百分之几百,如8核上限为800%

另外,kswapdmmcqd系统关键线程CPU线程过大,往往伴随系统回收资源,影响到应用进程

通过对ANR信息的解读可以更佳全面的帮助我们定位ANR问题。

4.3 Logcat消息

线上如果记录了Logcat打印消息,着重从以下方面去看问题

  • onTrimeMemory:连续的onTrimMemory 往往说明APP的内存不足可能系统资源不足造成ANR
  • Slow operation Slow delivery 出现该情况系统性能受限。

5 结

从ANR产生的原因,系统处理ANR,应用层监听ANR,应对ANR应用侧比较全面的监控主线程的任务调度以及为了解决ANR采集系统信息最后给出了分析解决ANR问题的总体思路。

针对ANR问题,这些还远远不够,这里只是一个总体的框架,希望本文更全面的看待解决ANR问题有帮助。


根据不同的性能监控问题,我们需要采用不同的性能优化手段,而目前还是有些人群对于性能优化中间的一些优化手段掌握的不是很熟练,因此针对性能优化中间的所有不同类型的优化手段进行了归类整理,有启动优化、内存优化、网络优化、卡顿优化、存储优化……等,整合成名为《Android 性能优化核心知识点手册》,大家可以参考下:

《APP 性能调优进阶手册》:https://qr18.cn/FVlo89

启动优化

内存优化

UI优化

网络优化

Bitmap优化与图片压缩优化

多线程并发优化与数据传输效率优化

体积包优化

《Android 性能调优核心笔记汇总》:https://qr18.cn/FVlo89

《Android 性能监控框架》:https://qr18.cn/FVlo89

相关文章:

Android 性能优化——ANR监控与解决

作者&#xff1a;Drummor 1 哪来的ANR ANR(Application Not responding):如果 Android 应用的界面线程处于阻塞状态的时间过长&#xff0c;会触发“应用无响应”(ANR) 错误。如果应用位于前台&#xff0c;系统会向用户显示一个对话框。ANR 对话框会为用户提供强制退出应用的选项…...

Machine Learning-Ex3(吴恩达课后习题)Multi-class Classification and Neural Networks

目录 1. Multi-class Classification 1.1 Dataset 1.2 Visualizing the data 1.3 Vectorizing Logistic Regression 1.3.1 Vectorizing the cost function&#xff08;no regularization&#xff09; 1.3.2 Vectorizing the gradient&#xff08;no regularization&#…...

【Java】SpringBoot事务回滚规则

SpringBoot事务回滚规则SpringBoot事务回滚规则SpringBoot事务回滚规则 在SpringBoot中&#xff0c;如果一个方法被声明为Transactional&#xff0c;则会开启一个事务。如果这个方法中的任何一个步骤失败了&#xff08;比如抛出了异常&#xff09;&#xff0c;则该事务将会回滚…...

使用cocopod就那么容易

第一节、配置coopod 打开终端替换ruby镜像源&#xff0c;系统自带的镜像源(gem sources --remove https://rubygems.org/)被墙挡住了或者&#xff08;https://ruby.taobao.org/&#xff09;已过期。需替换成新的镜像源。 1&#xff09;.先查看已有的镜像是否是&#xff1a;ht…...

第14届蓝桥杯C++B组省赛

文章目录A. 日期统计B. 01 串的熵C. 冶炼金属D. 飞机降落E. 接龙数列F. 岛屿个数G. 子串简写H. 整数删除I. 景区导游J. 砍树今年比去年难好多 Update 2023.4.10 反转了&#xff0c;炼金二分没写错&#xff0c;可以AC了 Update 2023.4.9 rnm退钱&#xff0c;把简单的都放后面…...

面向对象编程(进阶)3:方法的重写

目录 3.1 方法重写举例 Override使用说明&#xff1a; 3.2 方法重写的要求 3.3 小结&#xff1a;方法的重载与重写 &#xff08;1&#xff09;同一个类中 &#xff08;2&#xff09;父子类中 3.4 练习 父类的所有方法子类都会继承&#xff0c;但是当某个方法被继承到子类…...

2023年第十四届蓝桥杯Java_大学B组真题

Java_B组试题 A: 阶乘求和试题 B: 幸运数字试题 C: 数组分割试题 D: 矩形总面积试题 E: 蜗牛试题 F: 合并区域试题 G: 买二赠一试题 H: 合并石子试题 I: 最大开支试题 J: 魔法阵【考生须知】 考试开始后&#xff0c;选手首先下载题目&#xff0c;并使用考场现场公布的解压密码解…...

APIs --- DOM事件进阶

1. 事件流 事件流指的是事件完整执行过程中的流动路径 任意事件被触发时总会经历两个阶段&#xff1a;【捕获阶段】和【冒泡阶段】 事件捕获 概念&#xff1a;从DOM的根元素开始去执行对应的事件&#xff08;从外到里&#xff09; 捕获阶段是【从父到子】的传导过程 代码&…...

awk命令详解以及使用方法

awk命令详解以及使用方法 awk 是一种文本处理工具&#xff0c;它可以逐行扫描文本文件&#xff0c;根据用户指定的规则进行匹配和处理&#xff0c;并输出结果。awk 的名称来自于三位创始人 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的首字母缩写。 awk 通常用于处理以…...

vue-router3.0处理页面滚动部分源码分析

在使用vue-router3.0时候&#xff0c;会发现不同的路由之间来回切换&#xff0c;会滚动到上次浏览的位置&#xff0c;今天就来看看这部分的vue-router中的源码实现。 无论是基于hash还是history的路由切换&#xff0c;都对滚动进行了处理&#xff0c;这里分析其中一种即可。 无…...

走心Python实战应用:【requests+re 模块】快速下载原shen图片

人生苦短&#xff0c;我用python 这次给大家带来的是模块实战 以便大家理解学习 觉得写的好的话&#xff0c;可以给我多多点赞鸭~ 走心Python实战应用&#xff1a;【requestsre 模块】快速下载原shen图片一、理解Python requests 模块二、requests 方法三、ruqusets 模块实战…...

Comparable和Comparator的使用

在Java中&#xff0c;Comparable和Comparator都是用来实现对象排序的接口。 Comparable Comparable是一个内部比较器接口&#xff0c;它允许在类定义时对该类进行自然排序。当实现了Comparable接口的类的对象列表被传递给Collections.sort()方法时&#xff0c;该方法将使用该…...

【OJ每日一练】1121 - 耐摔指数

文章目录 一、题目🔸题目描述🔸输入输出🔸样例二、思路解析三、代码参考作者:KJ.JK🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🍂个人博客首页: KJ.JK 💖系列专栏:OJ每日一练 一、题目 🔸题目描述 x星球的居民脾气不太好,但好在他…...

vue项目Agora声网实现一对一视频聊天Demo示例(Agora声网实战及agora-rtc-vue使用,新增在线预览地址)

最终效果 在线预览地址 一、声网简介---->请查看官网 二、声网注册---->请自行百度&#xff08;创建音视频连接需要在Agora注册属于您的appid&#xff09; 三、具体实现视频聊天步骤 1、 实现音视频通话基本逻辑 1、创建对象 调用 createClient 方法创建 AgoraRTCCli…...

集成时间序列模型提高预测精度

使用Catboost从RNN、ARIMA和Prophet模型中提取信号进行预测 集成各种弱学习器可以提高预测精度&#xff0c;但是如果我们的模型已经很强大了&#xff0c;集成学习往往也能够起到锦上添花的作用。流行的机器学习库scikit-learn提供了一个StackingRegressor&#xff0c;可以用于…...

(详细)《美国节日》:某月的第几个星期几

目录 一、题目描述&#xff1a; 二、思路&#xff1a; 1、给定 年月日&#xff0c;如何知道这天是星期几&#xff1f; 2、已知这个月的第一天是星期几&#xff0c;如何知道第三个星期一是几号&#xff1f; 3、最后一个星期一 三、思路总结 四、代码 一、题目描述&#xf…...

架构设计的历史背景

架构设计的历史背景 在探讨架构设计的历史背景时&#xff0c;了解软件开发进化的历史是一个重要的起点。了解软件开发的演变过程可以帮助我们更好地理解架构设计的起源和发展。现在&#xff0c;让我们来简要回顾一下软件开发的历史&#xff0c;并探索软件架构出现的背景。 首先…...

C#,初学琼林(06)——组合数的算法、数据溢出问题的解决方法及相关C#源代码

1 排列permutation 排列&#xff0c;一般地&#xff0c;从n个不同元素中取出m&#xff08;m≤n&#xff09;个元素&#xff0c;按照一定的顺序排成一列&#xff0c;叫做从n个元素中取出m个元素的一个排列(permutation)。特别地&#xff0c;当mn时&#xff0c;这个排列被称作全…...

MySQL数据库——绘制E-R图:数据库概要设计阶段

在MySQL数据库的概要设计阶段&#xff0c;绘制E-R图是非常重要的一步。E-R图&#xff08;实体关系图&#xff09;是一种图形化的工具&#xff0c;用于描述数据库中实体之间的关系。 以下是在MySQL数据库概要设计阶段绘制E-R图的步骤&#xff1a; 确定实体&#xff1a;在MySQL数…...

对类和对象的理解

对象&#xff1a;对象是人们要进行研究的任何事物&#xff0c;它不仅能表示具体的事物&#xff0c;还能表示抽象的规则、计划或事件。对象具有状态&#xff0c;一个对象用数据值来描述它的状态。对象还有操作&#xff0c;用于改变对象的状态&#xff0c;对象及其操作就是对象的…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...