ANR系列之八:疑难ANR问题处理记录

news2024/11/17 11:31:15

前言:

本文仅是记录作者自身处理过的ANR问题,以及帮助他人解决过的ANR问题。本文中所介绍的ANR处理记录仅供参考,并不适用所有场景。并且最终结论和分析并不一定就是绝对正确的。

案例1.页面切换时前台应用焦点未获得

案例编号:略

案例描述:

自动化验证的时候,偶现ANR,ANR提示如下:

Subject: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)

案例分析:

这个ANR错误代表应用切换到了前台,但是被切换到前台的应用并没有获取到焦点。仔细查看相关的log日志,如下:

//关闭返回
03-08 04:58:26.820 2588 2588 I XxxxLink_HU :  =>> close click.

//AMS执行切换
03-08 04:58:26.830 1038 1101 W ActivityManager : Resuming top, waiting visible to hide: ActivityRecord{5480ff u0 com.yflink.client/com.xxxx.entrance.ui.CopyScreenMainActivity t40}
03-08 04:58:26.830 1038 1101 W ActivityManager : Resume running: ActivityRecord{8e973ce u0 com.xxxx.launcher/.passenger.PassMainActivity t27} stopped=true visible=false
03-08 04:58:26.831 1038 1101 I am_set_resumed_activity : [0,com.xxxx.launcher/.passenger.PassMainActivity,resumeTopActivityInnerLocked]

//桌面响应
03-08 04:58:26.850 1460 1460 I am_on_resume_called : [0,com.xxxx.launcher.passenger.PassMainActivity,RESUME_ACTIVITY]
//切换完成
03-08 04:58:26.875 1038 2730 I WindowManager : finishDrawingWindow: Window{1632bf9 u0 com.xxxx.launcher/com.xxxx.launcher.passenger.PassMainActivity} mDrawState=DRAW_PENDING

//再次启动CopyScreenMainActivity
03-08 04:58:27.823 1038 2431 I ActivityManager : START u0 {flg=0x10000000 cmp=com.yflink.client/com.xxxx.entrance.ui.CopyScreenMainActivity} from uid 1000 from pid 1460

//执行newIntent流程
03-08 04:58:27.835 2588 2588 I am_on_resume_called : [0,com.xxxx.entrance.ui.CopyScreenMainActivity,performNewIntents]

//AMS执行切换,这时候PassMainActivity被暂停,CopyScreenMainActivity切换到前台。
03-08 04:58:27.854 1460 1460 I am_on_paused_called : [0,com.xxxx.launcher.passenger.PassMainActivity,performPause]
03-08 04:58:27.854 1038 1101 W ActivityManager : Resuming top, waiting visible to hide: ActivityRecord{8e973ce u0 com.xxxx.launcher/.passenger.PassMainActivity t27}
03-08 04:58:27.854 1038 1101 W ActivityManager : Resume running: ActivityRecord{5480ff u0 com.yflink.client/com.xxxx.entrance.ui.CopyScreenMainActivity t40} stopped=false visible=false
03-08 04:58:27.854 1038 1101 I am_set_resumed_activity : [0,com.yflink.client/com.xxxx.entrance.ui.CopyScreenMainActivity,resumeTopActivityInnerLocked]
//APP响应
03-08 04:58:27.903 2588 2588 I am_on_resume_called : [0,com.xxxx.entrance.ui.CopyScreenMainActivity,RESUME_ACTIVITY]

//这里缺少APP执行finishDrawingWindow的流程,说明window没有注册上。所以最大的可能性就是桌面没有释放
//桌面的Window响应注册
03-08 04:58:27.938 1038 7512 I WindowManager : finishDrawingWindow: Window{aba4e14 u0 com.xxxx.launcher} mDrawState=DRAW_PENDING

03-08 04:58:28.219 1460 1460 W IPSurfaceView : surfaceDestroyed
03-08 04:58:28.219 1460 1460 W IPSurfaceView : pause 清空动画
03-08 04:58:28.219 1460 1460 W IPSurfaceView : destroyThread called
03-08 04:58:28.220 1460 29148 W System.err : java.lang.InterruptedException
03-08 04:58:28.220 1460 29148 W System.err :   at java.lang.Object.wait(Native Method)
03-08 04:58:28.220 1460 29148 W System.err :   at java.lang.Object.wait(Object.java:422)
03-08 04:58:28.220 1460 29148 W System.err :   at com.xxxx.ipservicesdk.widget.IPSurfaceView.drawLoop(IPSurfaceView.java:360)
03-08 04:58:28.220 1460 29148 W System.err :   at com.xxxx.ipservicesdk.widget.IPSurfaceView.updateView(IPSurfaceView.java:284)
03-08 04:58:28.220 1460 29148 W System.err :   at com.xxxx.ipservicesdk.widget.IPSurfaceView$1.run(IPSurfaceView.java:163)
03-08 04:58:28.220 1460 29148 W System.err :   at java.lang.Thread.run(Thread.java:764)
03-08 04:58:28.220 1460 29148 W IPSurfaceView : update thread finished com.xxxx.ipservicesdk.widget.IPSurfaceView$1@e78b18c

//这里缺少CopyScreenMainActivity完成渲染的日志finishDrawingWindow,说明其没有正常注册窗口。
03-08 04:58:34.423 1038 2861 I WindowManager : finishDrawingWindow: Window{41c1228 u0 com.gameloft.android.BTCN.GloftA9BT/com.gameloft.android.BTCN.GloftA9BT.MainActivity} mDrawState=DRAW_PENDING
03-08 04:58:34.580 1038 7512 I WindowManager : finishDrawingWindow: Window{41c1228 u0 com.gameloft.android.BTCN.GloftA9BT/com.gameloft.android.BTCN.GloftA9BT.MainActivity} mDrawState=HAS_DRAWN

我们发现,页面切换的时候,理应被切换到前台的Activity执行了resume流程后,却没有执行finishDrawingWindow的流程,并且此时的CPU负载并不高。

详细查看页面切换后5S内的日志,发现有一个桌面悬浮框报错,并且是在渲染更新的时候,所以怀疑是这个悬浮框占据了焦点未释放。

在过去了6S之后,又跳转了下一个页面,这个页面是正常的流程。所以中间那5S的时间PassMainActivity并没有获取到焦点。

问题结论:

应用的Activity是复用的,切换到前台的时候,焦点被上一个应用的延时操作占据,所以导致注册了window之后并没有整的走dispatchDraw流程完成焦点的切换。

其实这个时候如果使用命令:adb shell dumpsys window 获取当前屏幕window的话,焦点应该在IPSurfaceView上面,不过因为是偶现,所以也只能推测。

解决方案是给IPSurfaceView的实现类添加Window的Flag:FLAG_NOT_FOCUSABLE。

案例2.跨进程通信的问题

案例编号:略

案例描述:

开机启动后不久,某些应用直接发生ANR,ANR提示如下:

Subject: Context.startForegroundService() did not then call Service.startForeground()

值得注意的是,此时的CPU负载是很高的。

问题分析:

首先看发生ANR时的负载,此时的CPU负载是很高的,总负载达到了70%以上。

CPU usage from 0ms to 20784ms later (2023-03-10 21:03:42.371 to 2023-03-10 21:04:03.155):
73% 514/surfaceflinger: 45% user + 28% kernel / faults: 5073 minor
51% 3075/com.xxxx.voice: 42% user + 9.4% kernel / faults: 202836 minor 131 major
30% 1483/com.xxxx.beanmap: 17% user + 13% kernel / faults: 49570 minor 12 major
24% 1167/system_server: 11% user + 12% kernel / faults: 20432 minor 2 major
23% 458/android.hardware.graphics.composer@2.2-service: 10% user + 12% kernel / faults: 36 minor
20% 1439/com.xxxx.adapterservice.server: 17% user + 3% kernel / faults: 26796 minor

接下来看ANR时的主线程堆栈,内容如下:

kernel: (couldn't read /proc/self/task/3582/stack)
native: #00 pc 000000000001f06c  /system/lib64/libc.so (syscall+28)
native: #01 pc 00000000000d724c  /system/lib64/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+148)
native: #02 pc 00000000005171b0  /system/lib64/libart.so (offset 449000) (_ZN3artL12GoToRunnableEPNS_6ThreadE.llvm.323061163+448)
native: #03 pc 0000000000516fac  /system/lib64/libart.so (offset 449000) (art::JniMethodEnd(unsigned int, art::Thread*)+28)
at android.os.BinderProxy.transactNative(Native method)
at android.os.BinderProxy.transact(Binder.java:1129)
at com.xxxx.accountstub.IAccountData$Stub$Proxy.isLogin(IAccountData.java:538)
at com.xxxx.accountstub.BeanAccountInfoManager.isLogin(BeanAccountInfoManager.java:250)
at com.xxxx.mediacenter.core_account.AccountInfoHub.isLogin(AccountInfoHub.java:231)
at com.xxxx.mediacenter.core_account.AccountInfoHub.getThirdAccountList(AccountInfoHub.java:156)
at com.xxxx.mediacenter.core_account.AccountInfoHub.access$600(AccountInfoHub.java:45)
at com.xxxx.mediacenter.core_account.AccountInfoHub$3.run(AccountInfoHub.java:142)

很明显,主线程中此时被阻塞了,阻塞的原因是正在通过binder进行跨进程通讯,但是作为binder的server端迟迟没有响应。

在仔细排查日志,发现作为server一方的那个进程,也正在执行初始化的流程中,所以没有办法响应。总结下来,其实就是开机启动后,有大量的进程执行自启动操作导致CPU被强占,并且由于相关之间还存在依赖关系,从而导致一些本来其实负载并不到的应用也产生了ANR问题。

案例结论:

这种问题,解决方案有两种,从技术上解决和从业务上解决。

从技术上解决:

1.binder通讯放到子线程处理,这样就不会阻塞主线程,但是这样治标不治本,用户仍然无法正常使用业务功能。

2.改为启动后台服务,后台服务的超时时间为200S。但是高版本对后台服务启动有很多限制,而且service未能按时启动仍然会影响业务。

所以从技术上解决,多是治标不治本的方案,并不是太好。

从业务逻辑上解决:

统一收口开机启动的应用,然后通过按需拉起和梯队拉起来解决。

1.取消各个应用的persistent属性,由一个三方应用应用来管控开机之后的拉起操作。至于为什么不放system_server,大家可以自行考虑下原因。

2.按需拉起。自然就是要看是否需要拉起,尤其是在开机阶段是否有必要拉起。

3.梯队拉起。则需要先梳理一下应用之间的相互依赖关系以及相关业务优先级,被依赖的应用以及业务优先级价值较高的被优先拉起。

我们选择的是后者,当然,这需要拉齐所有相关方,成本还是蛮高的,但是我们认为是值得的。

案例3.前台服务启动超时

案例编号:略

案例描述:

应用ANR,异常reason为:

Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{9c69e1d u0 com.xxxx.mediacenter.passenger/com.xxxx.mediacenter.mediacentermodel.BeanMediaStartService}

这个错误代表被第三方应用通过直接拉起service的方式启动前台服务,并且在service的onStartCommand被调用后的30秒内没有调用startForeground方法,此时系统会通知应用产生一个异常崩溃,但此时主线程卡顿超10S以上,就会出现这种类型的ANR。如果此时主线程不卡顿,那么就会产生一个崩溃。

案例分析:

这个仍然是启动前台服务导致的超时,但是分析下来,和问题2还是有区别的,因为此时整体负载并算很高。

查看ANR文件中的堆栈:

"main" prio=5 tid=1 Runnable
  | group="main" sCount=0 dsCount=0 flags=0 obj=0x7449cb08 self=0x71e9614c00
  | sysTid=3471 nice=0 cgrp=default sched=0/0 handle=0x726f25a550
  | state=R schedstat=( 2284943688 9496195780 2668 ) utm=174 stm=53 core=0 HZ=100
  | stack=0x7feac82000-0x7feac84000 stackSize=8MB
  | held mutexes= "mutator lock"(shared held)
  at java.lang.StringBuilder.append(StringBuilder.java:137)
  at java.util.Arrays.toString(Arrays.java:4511)
  at dalvik.system.DexPathList.toString(DexPathList.java:201)
  at java.lang.String.valueOf(String.java:2896)
  at java.lang.StringBuilder.append(StringBuilder.java:132)
  at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
  at com.iqy.iv.plugin.server.core.PluginClassLoader.findClass(PluginClassLoader.java:37)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
  at java.lang.Class.classForName(Native method)
  at java.lang.Class.forName(Class.java:453)
  at java.lang.Class.forName(Class.java:378)
  at com.qiyi.baselib.utils.device.DeviceUtil.isHarmonyOSByOsBrand(DeviceUtil.java:1089)
  at com.qiyi.baselib.utils.device.DeviceUtil.isHarmonyOs(DeviceUtil.java:1079)
  at org.qiyi.android.coreplayer.utils.CupidAdTool.setCupidSdkStatus(CupidAdTool.java:182)
  at org.qiyi.android.coreplayer.bigcore.BigCoreLibLoader.loadAndInitCup(BigCoreLibLoader.java:402)
  at org.qiyi.android.coreplayer.bigcore.BigCoreLibLoader.loadBigCoreSo(BigCoreLibLoader.java:114)
  at org.qiyi.android.coreplayer.bigcore.DLController.loadLib(DLController.java:533)
  at org.iqiyi.video.facade.LoadLibJob.doInitAndLoadLib(LoadLibJob.java:43)
  at org.iqiyi.video.facade.CarPlayerInit.initLibConfig(CarPlayerInit.java:69)
  at org.iqiyi.video.facade.CommonPlayerInit.initAppForQiyi(CommonPlayerInit.java:91)
  at org.iqiyi.video.facade.CarPlayerInit.initAppForQiyi(CarPlayerInit.java:48)
  at org.iqiyi.video.facede.QYAppFacede.init(QYAppFacede.java:142)
  at org.iqiyi.video.facede.QYAppFacede.initAppForQiyi(QYAppFacede.java:153)
  at com.qiyi.ivsdk.init.InitHelper.initNecessaryForPlayerSync(InitHelper.java:399)
  at com.qiyi.ivsdk.init.InitHelper.init(InitHelper.java:145)
  at com.iqy.iv.sdk.PlayerSdkImpl.initialize(unavailable:104)
  at com.iqy.iv.sdk.PlayerSdkProxy.initSDK(PlayerSdkProxy.java:159)
  at com.iqy.iv.sdk.PlayerSdkProxy$2.handleMessage(PlayerSdkProxy.java:78)
  at android.os.Handler.dispatchMessage(Handler.java:106)
  at android.os.Looper.loop(Looper.java:193)
  at android.app.ActivityThread.main(ActivityThread.java:6734)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:506)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

在进行爱奇艺SDK的初始化,并且在主线程,但是调用堆栈并不是在application或者service的onCreate方法,说明应该是通过handler.post等方法进行过切换。

上面说到,这种ANR,是30S内service中没有调用startForeground方法,并且30S后主线程处于阻塞状态无法处理系统传递过来的崩溃。出现了这种ANR,如果主线程不阻塞,那么就会Crash。

所以推测应该是下面两种场景之一导致的:

  1. onCreate方法并不耗时,onStartCommand中有调用startForeground的方法但是并未执行,推测执行onStartCommand方法前,有耗时操作。大概率应该是onCreate中post了耗时操作,并且阻塞了超过(30+10=40)秒。

  2. onStartCommand中没有调用startForeground方法,前30S主线程有可能并不阻塞,30S后主线程被阻塞住,从而产生了ANR。

最终通过查看相关日志,确定属于上面的场景1,并且通过分析确定,单单PlayerSdkProxy.initSDK方法耗时并不是很多,但是onCreate中通过post添加了很多耗时任务,导致累计超时。

案例结论:

解决方案很简单,按需加载,没有必要在service启动的时候一下子初始化那么多的SDK。改成懒加载机制,等service走完生命周期创建后在初始化。

问题4.隐藏的动画导致ANR

案例编号:76621

案例描述:

仍然是自动化验证,发现进入某个应用之后,很容易发生ANR问题,并且该应用ANR之后,进入其它应用也极易发生ANR问题。

发生ANR的堆栈,指向系统注册窗口的时机。

at android.os.BinderProxy.transactNative(Native method)
at android.os.BinderProxy.transact(Binder.java:1129)
at android.view.IWindowSession$Stub$Proxy.addToDisplay(IWindowSession.java:825)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:757)
locked <0x06fcde80> (a android.view.ViewRootImpl)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
locked <0x0c75ecb9> (a java.lang.Object)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:95)

案例分析:

乍一看,既然阻塞到向系统注册的时候,那么应该是系统问题。但是这里有一个疑点,那就是为什么每次这个应用甲ANR之后(我们暂且称之为应用甲),都会影响到其它的,理论上应用之间是相互独立的才对。所以,就把方向放到应用甲和系统窗口交互之间的原因上,怀疑有可能应用甲和系统过分的交互导致系统侧过载,从而间接的影响了其他的应用。

我们观察当时的日志,发现多次ANR都是发生在从MainActivity跳转WebViewActivity的时候。

//1. MainActivity pasue,准备跳转
09-30 01:39:27.803 1112 2086 I am_pause_activity : [0,111178572,com.xxxx.scenemanage/.MainActivity,userLeaving=true]
09-30 01:39:27.808 8046 8046 I am_on_paused_called : [0,com.xxxx.scenemanage.MainActivity,performPause]
//2. 进入WebViewActivity
09-30 01:39:27.857 8046 8046 I am_on_create_called : [0,com.xxxx.scenemanage.webkit.WebViewActivity,performCreate]
09-30 01:39:30.505 8046 8046 I am_on_resume_called : [0,com.xxxx.scenemanage.webkit.WebViewActivity,RESUME_ACTIVITY]
//3. 发生ANR了
09-30 01:39:33.799 1112 1198 I InputDispatcher : Application is not responding: Window
{91f7011 u0 com.xxxx.scenemanage/com.xxxx.scenemanage.WebViewActivity}

所以,缩小范围,应该是MainActivity页面WebViewActivity的onResume之前,有大量和系统侧的交互。

虽然我们不能复现当时的ANR场景,但是我们按照这个流程走一遍,并且通过top命令和systemtrace进行观察,还是能发现一些端倪的。我们发现进入到MainActivity,并且切换到FragmentB之后,TOP中SF和应用甲的负载会持续维持在高位,这是很不正常的,因为此时页面是静止的。

600%cpu  67%user   2%nice  51%sys 511%idle   0%iow   7%irq   2%sirq   0%host    
  PID USER         PR  NI VIRT  RES  SHR S[%CPU] %MEM     TIME+ ARGS            
  500 system       -2  -8 2.0G  34M  26M S 44.6   0.3 679:20.26 surfaceflinger
  20461 system       -3  -3  57M  17M  13M S  29.3   0.1 269:44.60 com.xxxx.scenemanage
...

结合systemtrace的线程分析,发现即使页面处于静止状态,RenderThread仍持续在跑,说明应用甲的代码中有地方在持续请求刷新的操作。最简单的方案,自然是断点打到ThreadedRender的draw方法中,看看到底谁在调用,但是发现,静止状态下,这里并没有被执行,所以说明是另外的地方直接请求native的方法进行请求刷新操作。

所以怀疑方向有两个:1.代码中是否有调用SO的地方;2.是否有执行相关的动画。

查完代码后,发现方向1不存在这种可能性。于是查看动画相关的代码,这时候,终于发现了根因。

<LinearLayout>
    <com.xxxx.widget.loading.XxxxLoading
    android:id="@+id/loading"
    android:layout_alignBottom="@+id/xxx"
    android:layout_marginEnd="16dp"
    android:layout_toStartOf="@+id/xxxx" />
</LinearLayout>

切换到FragmentB后,XxxxLoading处于visible状态,但是由于不再屏幕范围内,所以对用户是无感的。但是其一直有执行相关的动作操作,从而导致不断的请求执行绘制流程,从而导致了系统侧SF处于高负载状态,最终从而导致了ANR的发生。

public void onAnimationUpdate(@Nullable PAGView view) {
   this.tryCover();
}

private final void tryCover() {
   if (XxxxLoading.this.willDraw) {
      XxxxLoading.this.setWillNotDraw(true);
      XxxxLoading.this.postInvalidate();
   }
}

案例结论:

解决方案很简单,默认隐藏XxxxLoading即可,XxxxLoading中设置为gone就不会走invalidate流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1118702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始学CAPL

从零开始学CAPL CAPL和C语言的关系和介绍C语言的基础语法常量变量标识符关键字数据类型整数数据字符数据实型数据(浮点数据)运算符以及优先级类型转换printf函数 选择程序结构设计if语句switch语句 循环结构程序设计while语句do……while语句for语句break和continue 数组函数 C…

VueComponent的原型对象

一、prototype 每一个构造函数身上又有一个prototype指向其原型对象。 如果我们在控制台输入如下代码&#xff0c;就能看到Vue构造函数的信息&#xff0c;在他身上可以找到prototype属性&#xff0c;指向的是Vue原型对象&#xff1a; 二、__proto__ 通过构造函数创建的实例对…

Mybatis拦截器

MyBatis插件介绍 MyBatis提供了一种插件(plugin)的功能&#xff0c;虽然叫做插件&#xff0c;但其实这是拦截器功能。 MyBatis允许使用者在映射语句执行过程中的某一些指定的节点进行拦截调用&#xff0c;通过织入拦截器&#xff0c;在不同节点修改一些执行过程中的关键属性&…

apache搭建静态网站,moongoose搭建网站后台,出现的跨域问题解决

文章目录 1&#xff0c;问题描述1.1&#xff0c;当网页和后台是不同服务时会产生跨域问题1.2&#xff0c;跨域问题 2&#xff0c;nginx端口转发解决跨域问题2.1&#xff0c;下载并安装nginx2.1.1&#xff0c;解压后如下所示2.1.2&#xff0c;进入解压目录后&#xff0c;执行配置…

SAP-QM-动态检验规则

Dynamic Modification Rule &#xff08;动态修改规则&#xff09; 1、决定样本大小的方式有3种&#xff1a; 手动输入比例大小采样过程 物料主数据质量视图 2、采样过程的创建方式有2种 跟批量大小有关系&#xff1a;百分比/AQL跟批量大小没有关系&#xff1a;固定值 而当…

Jetpack:014-Jetpack中的小红点

文章目录 1. 概念介绍2. 使用方法2.1 Badge2.2 BadgedBox 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack库中底部栏相关的内容&#xff0c;本章回中主要介绍 小红点。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01; 1. 概念介绍 我们在本章回中…

Android C/C++ native编程NDK开发中logcat的使用

Android C/C native编程NDK开发中logcat的使用 前言具体用法 前言 在NDK开发过程中&#xff0c;C/C层&#xff0c;需要对代码进行一些调试&#xff0c;日志打印是我们解决异常或崩溃的重要手段&#xff0c;这里我就简单介绍下日志打印三步走。 首先我们先看下官方文档关于日志…

渗透测试--JWT攻防(一)

JWT简介 JWT代表JSON Web Token&#xff0c;它是一种用于安全地在不同实体之间传递信息的开放标准&#xff08;RFC 7519&#xff09;。JWT通常用于身份验证和授权领域&#xff0c;以及在网络应用程序和服务之间传递声明&#xff08;claims&#xff09;信息。 JWT的常见用途包括…

S7-1200通过CM CANopen模块与KINCO伺服连接

CM CANopen模块简介 CM CANopen模块&#xff08;Profinet转CANopen&#xff09;来自瑞典HMS &#xff0c;由西 门子授权HMS公司开发&#xff0c;与S7-1200完美兼容。 可做为S7-1200与CANopen/CAN设备之间的桥梁&#xff0c;能够联接任意 CANopen或CAN 2.0A设备到SIMATIC S7-1…

聊聊分布式架构10——Zookeeper入门详解

目录 01ZooKeeper的ZAB协议 ZAB协议概念 ZAB协议基本模式 消息广播 崩溃恢复 选举出新的Leader服务器 数据同步 02Zookeeper的核心 ZooKeeper 的核心特点 ZooKeeper 的核心组件 选举算法概述 服务器启动时的Leader选举 服务器运行期间的Leader选举 03ZooKeeper的…

PT100温度传感器

热电阻是中低温区&#xfe61;常用的一种温度检测器。它的主要特点是测量精度高&#xff0c;性能稳定。其中铂热电阻的测量精确度是&#xfe61;高的&#xff0c;它不仅广泛应用于工业测温&#xff0c;而且被制成标准的基准仪。金属热电阻的感温元件有石英套管十字骨架结构&…

智能洗地机哪个牌子好用?智能洗地机品牌排行榜

为了偷懒人类发明了扫把、拖把等手动清洁工具&#xff0c;随着技术的进步出现了吸尘器、扫地机器人等等智能产品&#xff0c;近几年洗地机又以快速、直接、高效对市场进行了“颠覆”&#xff0c;如何快速在洗地机市场中挑选到适合自己的智能洗地机呢&#xff0c;我们一起来看看…

2023-10-18 LeetCode每日一题(执行 K 次操作后的最大分数)

2023-10-18每日一题 一、题目编号 2530. 执行 K 次操作后的最大分数二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。你的 起始分数 为 0 。 在一步 操作 中&#xff1a; 选出一个满足 0 < i < nums.length 的…

node快速搭建一个学习资料共享平台

概述 本文要实现的功能比较简单&#xff1a;1、将想要共享的文件分文件夹的组织起来&#xff1b;2、别人可以通过界面进行搜索&#xff1b;3、可以在线预览或下载文件。基于这样的需求&#xff0c;本文分享通过node如何实现这样的功能。 实现效果 实现 1. node端服务 node端…

QT 操作Windows系统服务

Windows服务是在Windows操作系统上运行的后台应用程序&#xff0c;它们在系统启动时自动启动&#xff0c;并在后台持续运行&#xff0c;不需要用户交互。Windows服务的作用包括但不限于以下几个方面&#xff1a;1. 提供系统功能&#xff1a;许多Windows服务提供了系统级的功能和…

【Java题】实现继承和多态的例子

一&#xff1a;题目 1.员工类Employee&#xff1a; &#xff08;1&#xff09;私有成员变量&#xff1a;姓名&#xff0c;年龄&#xff0c;工资 &#xff08;2&#xff09;提供无参&#xff0c;有参构造 &#xff08;3&#xff09;成员方法&#xff1a;work()方法——员工工作 …

【算法|动态规划No.28】leetcode1312. 让字符串成为回文串的最少插入次数

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

lv8 嵌入式开发-网络编程开发 19 原始套接字

目录 1 链路层原始套接字用法 1.1 利用原始套接字实现类似wireshark的功能 1.2 利用原始套接字实现ping命令 2 网络层原始套接字用法 2.1 TCP原始套接字用法 1 链路层原始套接字用法 Linux中的原始套接字&#xff08;Raw Socket&#xff09;是一种高级套接字类型&#xff…

YOLOv5涨点必备!改进损失函数EIoU,SIoU,AlphaIoU,FocalEIoU,Wise-IoU

目录 一&#xff0c;改进损失函数的作用 二&#xff0c;具体实现 一&#xff0c;改进损失函数的作用 YOLOv5损失函数的作用是衡量预测框与真实框之间的差异&#xff0c;并根据这些差异来更新模型的参数。它帮助模型学习如何准确地检测和定位目标物体&#xff0c;从而提高检测…

【分类讨论】CF1747D

Problem - D - Codeforces 题意 思路 一看这个做法一定就是分类讨论 先判无解 显然&#xff0c;如果区间异或和不是0一定无解 如果区间内全是0&#xff0c;答案一定是0 之后怎么讨论 注意到需要讨论区间长度 如果长度是奇数&#xff0c;那么直接操作即可&#xff0c;答…