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

GC终结标记 SuspendEE 是怎么回事

一:背景

1. 讲故事

写这篇是起源于训练营里有位朋友提到了一个问题,在 !t -special 输出中有一个 SuspendEE 字样,这个字样在 coreclr 中怎么弄的?输出如下:


0:000> !t -special
ThreadCount:      3
UnstartedThread:  0
BackgroundThread: 2
PendingThread:    0
DeadThread:       0
Hosted Runtime:   noLock  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception0    1     4ab0 000001CC44E5C490    2a020 Cooperative 0000000000000000:0000000000000000 000001cc44e520d0 -00001 MTA (GC) 11    2     19d8 000001CC44E84700    21220 Preemptive  0000000000000000:0000000000000000 000001cc44e520d0 -00001 Ukn (Finalizer) 12    3     6668 000001CC44ED4520    2b220 Preemptive  0000000000000000:0000000000000000 000001cc44e520d0 -00001 MTA OSID Special thread type0 4ab0 SuspendEE 10 3b6c DbgHelper 11 19d8 Finalizer 

哈哈,其实我特别能理解,很多人学了高级调试之后好奇心会爆棚,看啥都想探究底层,有一种技术上的重生,这篇我们就好好聊一聊。

二:WinDbg 分析

1. SuspendEE 标记是什么

这个单词全称为 Suspend Engine Execution, 即 冻结执行引擎 ,那冻结执行引擎的入口方法在哪里呢?这个考验着你对GC运作骨架图的认识,在 coreclr 源码中有一个骨架图,简化后如下:

GarbageCollectGeneration(){SuspendEE();garbage_collect();RestartEE();}garbage_collect(){generation_to_condemn();gc1();}

上面的 SuspendEE() 即 SOS 中的 SuspendEE 标记的入口函数,接下来我们深入探究下这个方法。

2. SuspendEE 到底做了什么

如果你仔细阅读过 SuspendEE() 方法的源代码,你会发现核心枚举变量是 ThreadType_DynamicSuspendEE,它起到了定乾坤的作用,参考代码如下:


thread_local size_t t_ThreadType;void ThreadSuspend::SuspendEE(SUSPEND_REASON reason)
{// set tls flags for compat with SOSClrFlsSetThreadType(ThreadType_DynamicSuspendEE);
}void ClrFlsSetThreadType(TlsThreadTypeFlag flag)
{t_ThreadType |= flag;gCurrentThreadInfo.m_EETlsData = (void**)&t_ThreadType - TlsIdx_ThreadType;
}enum PredefinedTlsSlots
{TlsIdx_ThreadType = 11 // bit flags to indicate special thread's type
};enum TlsThreadTypeFlag // flag used for thread type in Tls data
{ThreadType_DynamicSuspendEE = 0x00000020,
}

从上面的代码中可以看到 t_ThreadType 是一个 C++ 级的线程本地存储,意味着每一个线程都有其备份,同时它也是 SuspendEE 标记的核心来源,如果 m_EETlsData 的第 11号 槽位为 0x20 的时候, SuspendEE 标记就会被成功打下,并且可以通过 gCurrentThreadInfo.m_EETlsData 变量去跟踪来源,有了这么多信息之后,接下来就可以代码验证了。

三:案例验证

1. 一段测试代码

代码非常简单,就是一个简单的手工 GC触发。

internal class Program{static void Main(string[] args){Debugger.Break();GC.Collect();Console.ReadLine();}}

接下来使用 windbg 在入口的 SuspendEE 方法上下断点 bp coreclr!ThreadSuspend::SuspendEE 观察,截图如下:

一旦将 ThreadType_DynamicSuspendEE=0x20 赋值之后,接下来用 windbg 去做个验证。


0:000> x coreclr!*gCurrentThreadInfo*
000001a1`668ee8c0 coreclr!gCurrentThreadInfo = struct ThreadLocalInfo0:000> dx -id 0,0 -r1 (*((coreclr!ThreadLocalInfo *)0x1a1668ee8c0))
(*((coreclr!ThreadLocalInfo *)0x1a1668ee8c0))                 [Type: ThreadLocalInfo][+0x000] m_pThread        : 0x1a166902e50 [Type: Thread *][+0x008] m_pAppDomain     : 0x1a166948b40 [Type: AppDomain *][+0x010] m_EETlsData      : 0x1a1668ee880 [Type: void * *]0:000> dp 0x1a1668ee880
000001a1`668ee880  00000000`00000000 00000000`00000000
000001a1`668ee890  00000000`00000000 00000000`00000000
000001a1`668ee8a0  00000000`00000000 00000000`00000000
000001a1`668ee8b0  00000000`00000000 00000000`00000000
000001a1`668ee8c0  000001a1`66902e50 000001a1`66948b40
000001a1`668ee8d0  000001a1`668ee880 00000000`00000020

从上面输出可以看到 000001a1668ee8d0+0x8 地址的内容已经被成功种下,相信这时候 !t -special 也能拿到标记了。


0:000> !t -specialLock  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception0    1     640c 000001A166902E50    2a020 Preemptive  000001A16B0094A8:000001A16B00A5B8 000001a166948b40 -00001 MTA (GC) 11    2     3e50 000001A16692B2D0    21220 Preemptive  0000000000000000:0000000000000000 000001a166948b40 -00001 Ukn (Finalizer) 12    3     6a24 000001A16699F8F0    2b220 Preemptive  0000000000000000:0000000000000000 000001a166948b40 -00001 MTA OSID Special thread type0 640c SuspendEE 10 76b0 DbgHelper 11 3e50 Finalizer 

那这个 0x20 什么时候被拿掉呢? 这个在源码中也能找到相应的答案,继续 go 运行,输出如下:


void ClrFlsClearThreadType(TlsThreadTypeFlag flag)
{t_ThreadType &= ~flag;
}0:012> dp 0x1a1668ee880
000001a1`668ee880  00000000`00000000 00000000`00000000
000001a1`668ee890  00000000`00000000 00000000`00000000
000001a1`668ee8a0  00000000`00000000 00000000`00000000
000001a1`668ee8b0  00000000`00000000 00000000`00000000
000001a1`668ee8c0  000001a1`66902e50 000001a1`66948b40
000001a1`668ee8d0  000001a1`668ee880 00000000`00000000

当然如果你去寻找 sos 的源码实现,也会找到相应的答案。


HRESULT PrintSpecialThreads()
{...if (ThreadType & ThreadType_DynamicSuspendEE){type += "SuspendEE ";}...return Status;
}

四:总结

挖掘这个标记的前世今生回头看其实还是挺有意思的,coreclr 居然新增了 m_EETlsData 字段来给 sos 做妥协,哈哈,这彰显了 sos 一等公民的地位。

相关文章:

GC终结标记 SuspendEE 是怎么回事

一:背景 1. 讲故事 写这篇是起源于训练营里有位朋友提到了一个问题,在 !t -special 输出中有一个 SuspendEE 字样,这个字样在 coreclr 中怎么弄的?输出如下: 0:000> !t -special ThreadCount: 3 UnstartedTh…...

Ubuntu 中GCC交叉编译工具链安装

​ Ubuntu 自带的 gcc 编译器是针对 X86 架构的,如果要编译的是 ARM 架构的代码,就需要一个在 X86 架构的 PC 上运行,可以编译 ARM 架 构代码的 GCC 编译器,这个编译器就叫做交叉编译器,总结一下交叉编译器就是&#x…...

JEXL(Java Expression Language)用法概览

JEXL(Java Expression Language)是一个用于在Java应用程序中解析和执行表达式的库。JEXL的设计目的是通过提供一种类似于脚本语言的语法,使得可以在应用程序中动态地计算表达式的值。JEXL常用于模板引擎、规则引擎和配置文件等场景。 下面介…...

NC 完全二叉树结点数

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 给定一棵完全…...

点灯案例优化(二) 利用位运算修改特定位

前面,我们对点灯代码进行了第一次优化,效果如下 尽管第一次优化以后代码可读性确实高了不少,也看起来更加简洁,但是,这里仍旧存在一个很严重的问题:就在每一个表达式右边,我们给寄存器的数据赋值…...

【C++备忘录】

记录一些C比较好用的代码块&#xff0c;方便自个查看。 使用std::copy 快速打印序列 #include <iostream> #include <algorithm> #include <iterator>int main() {int a[5] { 1, 2, 3, 4, 5 };copy(begin(a), end(a), ostream_iterator<int>(cout, …...

java编程 斐波拉契数列算法集锦【斐波拉契数列】【下】【集合类】【Stream函数式编程】

斐波那契数列&#xff08;Fibonacci sequence&#xff09;&#xff0c;又称黄金分割数列&#xff0c;是一个非常经典的递归问题。斐波那契数列的算法描述&#xff1a; 斐波那契数列&#xff0c;一个令人着迷而又充满神秘色彩的数字序列&#xff0c;它以0和1作为起始&#xff…...

智慧园区三维可视化平台

背景 随着物联网、人工智能等新一代信息技术的发展&#xff0c;数字孪生技术逐渐成为实现这一目标的关键工具。数字孪生技术能够对物理世界进行高精度、全要素的映射&#xff0c;并实时动态反映其变化情况&#xff0c;从而为园区提供精准的管理和服务。 方案简介 智慧园区数字…...

Redis 有序集合【实现排行榜】

使用 Redis 的 Sorted Set 数据结构可以非常高效地实现实时排行榜功能。Sorted Set 允许将元素按分数进行排序&#xff0c;同时支持插入、删除和查询操作&#xff0c;且这些操作的时间复杂度较低&#xff0c;非常适合处理高并发的场景。 实现思路 插入操作&#xff1a;当用户…...

ORACLE数据库管理系统介绍

1.ORACLE的特点: 可移植性 ORACLE采用C语言开发而成,故产品与硬件和操作系统具有很强的独立性。从大型机到微机上都可运行ORACLE的产品。可在UNIX、DOS、Windows等操作系统上运行。可兼容性 由于采用了国际标准的数据查询语言SQL,与IBM的SQL/DS、DB2等均兼容。并提供读取其它…...

C# 中Linq探讨 Or条件拼接

在C#中&#xff0c;没有直接内置于.NET Core或.NET Framework中的NuGet包能够直接“拼接”LINQ的OR条件&#xff0c;因为LINQ本身设计为一种声明式编程模型&#xff0c;用于查询数据集合。然而&#xff0c;你可以通过一些方式来实现多个条件以OR逻辑组合的效果&#xff0c;而不…...

有关应用层面试题有关库的思维导体

面试题目&#xff1a; TCP通信中3次握手和四次挥手&#xff1f; 答&#xff1a; 第一次握手&#xff1a;客户端发送SYN包&#xff08;SYN1, seq0&#xff09;给服务器&#xff0c;并进入SYN_SENT状态&#xff0c;等待服务器返回确认包。第二次握手&#xff1a;服务器接收到S…...

记一次 SAP BP 编号范围错误引发的一个问题 GET_NRIV_LINE

本来想着循着错误提示去排查&#xff0c;但是还是想看看业务发生了什么&#xff0c;他们的操作是否有问题&#xff0c;不经意间发现 号码段是有问题的&#xff0c;由此大概可以判断是他们编号范围和类型之间的问题 角色和分组是否一致的&#xff0c;如果不一致就发生了以上错误…...

(17)ELK大型储存库的搭建

前言&#xff1a; els是大型数据储存体系&#xff0c;类似于一种分片式存储方式。elasticsearch有强大的查询功能&#xff0c;基于java开发的工具&#xff0c;结合logstash收集工具&#xff0c;收集数据。kibana图形化展示数据&#xff0c;可以很好在大量的消息中准确的找到符…...

每日一问:Kafka消息丢失与堆积问题分析(简化版)

Kafka 消息系统问题解析 在本篇博客中&#xff0c;我们将深入探讨 Kafka 中常见的两大问题&#xff1a;消息丢失和消息堆积。首先&#xff0c;我们将简要介绍 Kafka 的基本工作原理&#xff0c;随后分别分析消息丢失和堆积的原因&#xff0c;并提供针对性的解决方案。 关于其详…...

C语言中函数sizeof和strlen区别

sizeof和strlen是C语言中的两个常用函数&#xff0c;它们的作用和使用方式有所不同。 sizeof sizeof是一个运算符而非函数&#xff0c;用于计算数据类型或变量占用的字节数。它可以计算任意数据类型&#xff08;包括基本类型、自定义结构体、数组等&#xff09;的大小。例如&…...

RAG与LLM原理及实践(14)---- Python + MinIO + Kafka进阶

目录 背景 根因分析 配置 构造 创建 network 构造 zookeeper 构造 kafka 参数构造 原理解析 图解 全过程解析 工具使用 kafkacat 查看 broker python 实现 python send + kafka recv python 代码 kafka recv 运行效果 python recv + kafka send python 代…...

接口自动化-代码实现

接口自动化基础 1、接口自动化测试 接口自动化&#xff1a;使用工具或代码代替人对接口进行测试的技术测试目的&#xff1a; 防止开发修改代码时引入新的问题测试时机&#xff1a; 开发进行系统测试转测前&#xff0c;可以先进行接口自动化脚本的编写开发进行系统测试转测后&…...

如何查看linux大文件

文章目录 一、查看存储情况二、查看指定路径下的文件大小查看临时文件和日志的大小 三、查找home目录下文件大小大于100M的大文件四、查看INNODE使用情况五、查看进程使用情况查看所有进程查看特定进程杀死相关进程 六、清除缓存操作七、 查看docker的硬盘占用情况详细查看 一、…...

生成式人工智能服务大模型备案答疑

问&#xff1a;大模型备案范围 答&#xff1a;利用生成式人工智能技术向中华人民共和国境内公众提供生成文本、图片、音频、视频等内容的服务&#xff0c;适用本办法。 未向境内公众提供生成式人工智能服务的&#xff0c;不适用本办法的规定。 ps&#xff1a;生成式人工智能…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...