Android死锁处理

什么是死锁

在这里插入图片描述

android死锁的处理方式

Android系统的Framework层有一个WatchDog用于定期检测关键系统服务是否发生死锁。WatchDog功能主要是分析系统核心服务和重要线程是否处于Blocked状态。

源码见:WatchDog

基本原理就是定期轮询检测系统中核心的线程的状态
检测到卡死后,将相关对应的线程,进程及其他软硬件信息输出。

Android开发过程中死锁分析方法

在Android开发中最容易碰到的死锁表现形式ANR。产生ANR的原因很多,死锁只是其中一种。如果ANR发生,对应的应用会收到SIGQUIT异常终止信号,dalvik虚拟机就会自动在/data/anr/目录下生成trace.txt(Android8.1以后文件名不是这个了)文件,这个文件记录了在发生ANR时刻系统各个线程的执行状态,trace文件中记录的线程执行状态详细描述了各个线程加锁等待的情况,通过分析,可以相对容易的找到发生死锁所在的线程及代码。

anr的情况下主线程死锁导致的问题,可以通过ANR的trace文件分析,如果是非主线程呢,这种死锁一般很难察觉,但是这种死锁有时候也会造成很严重的后果,因为线程可能一直在占用某些资源,比如端口,数据库连接,文件句柄等。对于普通的java程序,JVM提供了jstack工具,可以将线程信息dump出来进行分析。虽然Android系统中没有提供类似jstack的工具,但是下面有两种方法来检查是否有线程发生死锁。

使用Android Studio的调试工具

首先通过工具栏Run->Attach to Process 或者快捷入口
在这里插入图片描述
,将App的进程attach进去。
然后在Android Debugger窗口中,找到Get Thread Dump按钮,点击后,稍等片刻,Androd Studio就会将对应调试进程的线程堆栈信息dump出来。
在这里插入图片描述
下图就是得到的线程信息,这样就可以分析线程中的死锁了。
在这里插入图片描述

借助ANR机制

Android应用发生ANR时,系统会发出SIGQUIT信号给发生ANR的进程。发现被监控线程卡死时,可以主动向系统发送SIGQUIT信号,使/data/anr/traces.txt文件生成,这样可以得到一个和ANR日志相同的线程堆栈信息,用来分析是否发生了死锁的问题。

例子如下:

首先通过ps命令拿到想要进行分析的进程id

adb shell ps | grep com.sohu.sohuvideo

在这里插入图片描述

这取主进程 id : 22841,执行如下命令

adb shell run-as com.sohu.sohuvideo kill -3 22841

紧接着会在logcat中看到日志 com.sohu.sohuvideo I/.sohu.sohuvide: Wrote stack traces to ‘[tombstoned]’,这时我们的trace文件便已经生成好了(这里需要注意Android8.1之前输出的日志为 Wrote stack traces to traces.txt)。

  • run-as 命令需要在debug包才能使用,Release包不能使用。

Android8.1之前的系统,通过 adb pull /data/anr/traces.txt 命令直接将文件拿到了,8.1之后系统trace文件便没有权限直接可以拿到了。通过adb shell直接进入手机目录查看发现,可以发现申城的dump文件为dumptrace_YbVvLP,。
在这里插入图片描述
使用下面的命令可以导出对应的文件。

adb shell cat /data/anr/dumptrace_YbVvLP > ~/Desktop/dump

refers:

https://zhuanlan.zhihu.com/p/152049739

### .NET 平台中处理死锁问题的解决方案 在.NET平台中,死锁是一种常见的并发编程问题。为了有效地解决或避免死锁,可以从以下几个方面入手: #### 1. **合理设计资源访问顺序** 为了避免死锁的发生,应确保所有线程按照一致的顺序获取共享资源。如果所有的线程都遵循相同的加锁顺序,则不会形成循环等待条件[^3]。 #### 2. **使用超时机制** 当尝试获取锁时,可以设置一个最大等待时间。如果超过此时间仍未成功获取锁,则放弃当前操作并释放已持有的其他锁。这种方法类似于Android中的死锁解决方案[^4]。通过这种方式,即使某些线程未能按预期完成任务,也不会导致整个系统陷入永久阻塞状态。 #### 3. **采用高级同步原语** .NET提供了多种高级同步工具可以帮助开发者更轻松地管理多线程环境下的资源共享问题。例如`Monitor.TryEnter()`允许指定一个时间段去尝试进入临界区;还有像ReaderWriterLockSlim这样的类支持读写分离模式,在一定程度上减少了竞争冲突的可能性。 #### 4. **实现重试逻辑** 对于可能发生死锁的操作,应该考虑加入自动重试机制。即在线程因未满足特定条件而失败后的一段时间后再重新发起请求。这不仅有助于缓解瞬态错误的影响,也能间接防止长时间持有必要资源而导致潜在死锁风险增加的情况出现。 #### 5. **利用Task Parallel Library (TPL) 和 async/await** 现代C#开发推荐使用异步编程模型来代替传统的显式创建和控制线程方式。通过async/await关键字配合TPL库函数可以让代码更加简洁易懂的同时也降低了手动管理线程间协调工作的复杂度,从而减少人为失误造成死锁的概率。 #### 6. **死锁检测与恢复** 尽管前面提到的方法都可以有效降低死锁发生的几率,但在极其复杂的业务场景下仍难以做到绝对杜绝。因此还需要准备一套完善的应急措施——即所谓的“死锁检测与恢复”。具体做法包括但不限于定期扫描应用程序内部的状态以发现可能存在的互斥依赖关系链路,并及时介入解除僵局;或者预先定义好若干种可接受范围内的牺牲策略(比如终止某个不重要的后台作业),以便快速恢复正常服务流程[^2]。 ```csharp // 使用 Monitor.TryEnter 防止无限期等待 object lockA = new object(); object lockB = new object(); bool acquiredBothLocks = false; try { bool gotFirstLock = false; try { if(Monitor.TryEnter(lockA, TimeSpan.FromSeconds(5))) { // 尝试获取lockA最多五秒 gotFirstLock = true; if(!Monitor.TryEnter(lockB, TimeSpan.FromSeconds(5))) { // 如果没能同时拿到lockB就退出 throw new TimeoutException("Could not acquire both locks within the timeout period."); } // 成功获得了两个锁之后才到这里执行实际工作... Console.WriteLine("Successfully entered critical section!"); acquiredBothLocks = true; } else { throw new TimeoutException("Failed to enter first lock."); } } finally { if(gotFirstLock && !acquiredBothLocks){ Monitor.Exit(lockA); // 确保总是释放第一个锁以防泄漏 } } } catch(Exception ex){ Console.Error.WriteLine($"Error during locking operation:{ex.Message}"); } finally{ if(acquiredBothLocks){ Monitor.Exit(lockB); Monitor.Exit(lockA); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zeloas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值