Systrace 基础知识 - 锁竞争解读
参考连接:https://www.androidperformance.com/2019/12/06/Android-Systrace-Binder/
1.Systrace 显示的锁的信息
monitor contention with owner Binder:1605_B (4667) at void
com.android.server.wm.ActivityTaskManagerService.activityPaused(android.os.IBinder)
(ActivityTaskManagerService.java:1733) waiters=2 blocking from android.app.ActivityManager$StackInfo
com.android.server.wm.ActivityTaskManagerService.getFocusedStackInfo()(ActivityTaskManagerService.java:2064)
上面的话分两段来看,以 blocking 为分界线
1.1 第一段信息解读
monitor contention with owner Binder:1605_B (4667) at void
com.android.server.wm.ActivityTaskManagerService.activityPaused(android.os.IBinder)
(ActivityTaskManagerService.java:1733) waiters=2
Monitor 指的是当前锁对象的池,在 Java 中,每个对象都有两个池,锁(monitor)池和等待池:
锁池(同步队列 SynchronizedQueue ):假设线程 A 已经拥有了某个对象(注意:不是类 )的锁,而其它的线程想要调用这个对象的某个 synchronized 方法(或者 synchronized 块),由于这些线程在进入对象的 synchronized 方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程 A 拥有,所以这些线程就进入了该对象的锁池中。
这里用了争夺(contention)这个词,意思是这里由于在和目前对象的锁正被其他对象(Owner)所持有,所以没法得到该对象的锁的拥有权,所以进入该对象的锁池
Owner : 指的是当前拥有这个对象的锁的对象。这里是 Binder:1605_B,4667 是其线程 ID。
at 后面跟的是拥有这个对象的锁的对象正在做什么。这里是在执行 void com.android.server.wm.ActivityTaskManagerService.activityPaused 这个方法,其代码位置是 :ActivityTaskManagerService.java:1733 其对应的代码如下:
com/android/server/wm/ActivityTaskManagerService.java
@Override
public final void activityPaused(IBinder token) {final long origId = Binder.clearCallingIdentity();synchronized (mGlobalLock) { // 1733 是这一行ActivityStack stack = ActivityRecord.getStackLocked(token);if (stack != null) {stack.activityPausedLocked(token, false);}}Binder.restoreCallingIdentity(origId);
}
可以看到这里 synchronized (mGlobalLock) ,获取了 mGlobalLock 锁的拥有权,在他释放这个对象的锁之前,任何其他的调用 synchronized (mGlobalLock) 的地方都得在锁池中等待
waiters 值得是锁池里面正在等待锁的操作的个数;这里 waiters=2 表示目前锁池里面已经有一个操作在等待这个对象的锁释放了,加上这个的话就是 3 个了
1.2 第二段信息解读
blocking from android.app.ActivityManager$StackInfo com.android.server.wm.ActivityTaskManagerService.getFocusedStackInfo()(ActivityTaskManagerService.java:2064)
第二段信息相对来说简单一些,就是标识了当前被阻塞等锁的方法 , 这里是 ActivityManager 的 getFocusedStackInfo 被阻塞,其对应的代码
com/android/server/wm/ActivityTaskManagerService.java
@Override
public ActivityManager.StackInfo getFocusedStackInfo() throws RemoteException {enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");long ident = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) { // 2064 是这一行 ActivityStack focusedStack = getTopDisplayFocusedStack();if (focusedStack != null) {return mRootActivityContainer.getStackInfo(focusedStack.mStackId);}return null;}} finally {Binder.restoreCallingIdentity(ident);}
}
可以看到这里也是调用了 synchronized (ActivityManagerService.this) ,从而需要等待获取 ams 对象的锁拥有权
1.3 总结
上面这段话翻译过来就是ActivityTaskManagerService 的 getFocusedStackInfo 方法在执行过程中被阻塞,原因是因为执行同步方法块的时候,没有拿到同步对象的锁的拥有权;需要等待拥有同步对象的锁拥有权的另外一个方法ActivityTaskManagerService.activityPaused 执行完成后,才能拿到同步对象的锁的拥有权,然后继续执行
可以对照原文看上面的翻译
monitor contention with owner Binder:1605_B (4667)
at void com.android.server.wm.ActivityTaskManagerService.activityPaused(android.os.IBinder)(ActivityTaskManagerService.java:1733)
waiters=2
blocking from android.app.ActivityManager$StackInfo com.android.server.wm.ActivityTaskManagerService.getFocusedStackInfo()(ActivityTaskManagerService.java:2064)
2.等锁分析
还是上面那个 Systrace,Binder 信息里面显示 waiters=2,意味着前面还有两个操作在等锁释放,也就是说总共有三个操作都在等待 Binder:1605_B (4667) 释放锁,我们来看一下 Binder:1605_B 的执行情况
从上图可以看到,Binder:1605_B 正在执行 activityPaused,中间也有一些其他的 Binder 操作,最终 activityPaused 执行完成后,释放锁
下面我们就把这个逻辑里面的执行顺序理顺,包括两个 waiters
2.1 锁等待
上图中可以看到 mGlobalLock 这个对象锁的争夺情况
- Binder_1605_B 首先开始执行 activityPaused,这个方法中是要获取 mGlobalLock 对象锁的,由于此时mGlobalLock 没有竞争,所以 activityPaused 获取对象锁之后开始执行
- android.display 线程开始执行 checkVisibility 方法,这个方法也是要获取 mGlobalLock 对象锁的,但是此时Binder_1605_B 的 activityPaused 持有 mGlobalLock 对象锁 ,所以这里android.display 的 checkVisibility 开始等待,进入 sleep 状态
- android.anim线程开始执行 relayoutWindow 方法,这个方法也是要获取 mGlobalLock 对象锁的,但是此时Binder_1605_B 的 activityPaused 持有 mGlobalLock 对象锁 ,进入 sleep 状态
- android.bg 线程开始执行getFocusedStackInfo 方法,这个方法也是要获取 mGlobalLock 对象锁的,但是此时 Binder_1605_B
的 activityPaused 持有 mGlobalLock 对象锁 ,进入 sleep 状态
经过上面四步,就形成了 Binder_1605_B 线程在运行,其他三个争夺 mGlobalLock 对象锁失败的线程分别进入 sleep 状态,等待 Binder_1605_B 执行结束后释放 mGlobalLock 对象锁
2.2 锁释放
上图可以看到 mGlobalLock 锁的释放和后续的流程
- Binder_1605_B 线程的 activityPaused 执行结束,mGlobalLock 对象锁释放
- 第一个进入等待的android.display 线程开始执行 checkVisibility 方法 ,这里从 android.display线程的唤醒信息可以看到,是被 Binder_1605_B(4667) 唤醒的
- android.display 线程的checkVisibility 执行结束,mGlobalLock 对象锁释放
- 第二个进入等待的 android.anim 线程开始执行relayoutWindow 方法 ,这里从 android.anim 线程的唤醒信息可以看到,是被 android.display(1683) 唤醒的
- android.anim 线程的 relayoutWindow执行结束,mGlobalLock 对象锁释放
- 第三个进入等待的 android.bg 线程开始执行getFocusedStackInfo 方法 ,这里从 android.bg 线程的唤醒信息可以看到,是被
android.anim(1684) 唤醒的
经过上面 6 步,这一轮由于 mGlobalLock 对象锁引起的等锁现象结束。这里只是一个简单的例子,在实际情况下,SystemServer 中的 BInder 等锁情况会非常严重,经常 waiter 会到达 7 - 10 个,非常恐怖,比如下面这种:
Systrace 基础知识 - 锁竞争解读相关推荐
- Android Systrace 基础知识(10) - Binder 和锁竞争解读
本文是 Systrace 系列文章的第十篇,主要是对 Systrace 中的 Binder 和锁信息进行简单介绍,简单介绍了 Binder 的情况,介绍了 Systrace 中 Binder 通信的表 ...
- Android Systrace 基础知识(9)-MainThread 和 RenderThread 解读
本文是 Systrace 系列文章的第九篇,主要是是介绍 Android App 中的 MainThread 和 RenderThread,也就是大家熟悉的「主线程」和「渲染线程」.文章会从 Syst ...
- 【基础知识】~ 竞争/冒险
本章目录: 竞争/冒险 产生背景 什么是竞争? 什么是冒险? 二者的行为关系 4种消除竞争冒险常见的方法 编写代码如何避免产生竞争冒险? 声明 竞争/冒险 产生背景 信号经过逻辑门电路都需要一定的时间 ...
- Kotlin搞起来——2.基础知识
在上一节中简单的给大家介绍了下Kotlin的特点,以及结合自己实际项目 中的使用来帮助大家了解这门语言,其实真的没你想象中的那么难,本文打算 介绍的是Kotlin中基础相关的一些语法(用法),有个大概 ...
- 【知识科普】解读闪电/雷电网络,零基础秒懂!
知识科普,解读闪电/雷电网络,零基础秒懂! 闪电网络的技术是革命性的,将实现即时0手续费的小金额支付.第一步是解决扩容问题,第二部就是解决共通性问题,利用原子交换协议和不同链条的状态通道结合,进行不同 ...
- ap计算机基础知识讲解,AP计算机课程与考试解读
原标题:AP计算机课程与考试解读 随着计算机对各个科技领域的创新.创业影响越来越大,计算机科学Computer Science已经毫无疑问成为美国各个大学最为热门的申请专业.当然名校的计算机录取标准也 ...
- 事业单位计算机基础知识考纲,2016年天津事业单位考试计算机大纲解读
2016年天津事业单位考试计算机大纲解读 一.试卷组成 天津市2016年事业单位公开招聘管理岗位和通用性较强专业技术岗位人员笔试阶段公共科目为<职业能力测验>和<综合知识>(文 ...
- 2021-06-01 深入分析锁的基础知识
目录 一 对象在内存中的布局? 创建一个Object对象占用多少内存? 1.1 对象在内存中的布局? 1.2 创建一个Object对象占用多少内存? 二Safepoint(安全点)? 2.1 什么是s ...
- 游戏配音基础知识解读
游戏内的配音各式各样,种类繁多,配音赋予了游戏人物生命以及感情.游戏配音员个伟大的职业,他们让游戏人物有了鲜活的生命,配音也是一艺术,今天我们来聊聊游戏配音这门艺术的基础知识. 在为游戏配音的过程中, ...
最新文章
- python简易图形-python图形用户界面(四):教你实现一个简单实用的计时器
- miniui datagrid 隐藏列默认赋值_「小程序JAVA实战」 小程序默认加载的页面和生命周期(八)...
- 【机器学习实战】意大利Covid-19病毒感染数学模型及预测
- zookeeper -- 第四章 zookeeper watcher讲解
- 初始化懒惰关系以及何时使用它们的5种方法
- 腾讯视频如何缓存视频
- 【Linux基础】查看硬件信息-CPU
- 46个PPT下载丨QCon 2019年全球软件开发大会PPT
- web 缓存服务器 HTTP2 性能测试: nuster vs nginx
- Oracle 10g新特性——正则表达式(转)
- java后端开发项目流程_Java项目——后端笔记
- 写了一个wwwscan的路径生成工具
- 电脑驱动器中出现Winretools和ESP问题
- DOS BAT脚本批量打开Edge网页
- Android View 监听宿主生命周期
- 投屏时 仅电脑屏幕、复制、扩展、仅第二屏幕的区别
- 一名普通医护人员的抗疫日志
- word2013无法打开doc文件显示正在受保护视图中打开解决方法
- 如何修改win7上的mac地址
- 基于 SpringBoot + Vue 框架开发的网页版聊天室项目