如何获取GC(垃圾回收器)的STW(暂停)时间?

前言

在现代的容器化和微服务应用中,因为分布式的环境和错综复杂的调用关系,APM(Application Performance Monitoring 应用性能监控)显得尤为重要,它通过采集应用程序各种指标和请求链路,让你知道系统当前的状态和值得优化的点,另外能帮助你发现应用程序的异常,帮助你更方便的定位问题。
对于.NET这样带GC(Garbage Collector 垃圾回收器)的平台来说,GC的指标也尤为重要,采集可以帮助我们分析内存泄漏、优化系统性能等等。在公司内部已经可以采集比较全面的.NET GC指标,如下图所示。
5737b727d75aa48b0048c452cf3e9b60.png
在绝大多数场景它能满足要求,但是如果遇到某时某刻P95延时突然增大,异步任务突然超时,我们想排查这些异常是否因为GC的STW Time(Stop The World Time 指GC运行过程中所有线程被挂起的时间)过长导致的,就没有办法了,因为目前没有采集这些指标。
所以本文就带大家了解一下,如何采集.NET GC STW Time。

方法

如.NET内存性能分析指南中提到的一样,.NET Runtime在运行过程中会发布很多事件,这些事件代表了当前Runtime的运行状态,同样GC在运行过程中也会发布很多事件,我们可以使用PerfView工具来收集这样的一些事件。下面是WorkStationGC发生GC时的一个事件序列。

Microsoft-Windows-DotNETRuntime/GC/SuspendEEStart	//开始暂停托管线程运行Microsoft-Windows-DotNETRuntime/GC/SuspendEEStop	//暂停托管线程完成Microsoft-Windows-DotNETRuntime/GC/Start	// GC开始回收Microsoft-Windows-DotNETRuntime/GC/Stop		// GC回收结束Microsoft-Windows-DotNETRuntime/GC/RestartEEStart	//恢复之前暂停的托管线程Microsoft-Windows-DotNETRuntime/GC/RestartEEStop	//恢复托管线程运行完成

PS: 所有的事件都可以在.NET文档官方中找到,非常的全面。
SuspendEEStart(暂停托管线程运行)RestartEEStop(恢复托管线程运行完成)中经过的时间就是STW Time,我们只需要记录这两个事件的差值,就可以知道本次GC STW的时间有多长。
BGC的过程比WorkStationGC复杂的很多,但是一样是测量这两个事件花费的时间来采集STW Time,本文不做过多介绍。

使用EventSource采集

那么我们知道通过计算哪两个指标的差值来获得STW时间,那么应该如何通过代码来采集呢?
这里就需要知道EventSourceEventListener两个类,顾名思义我们可以通过EventSource来发布事件,使用EventListener来监听事件,在本文中我们也主要使用EventListener来收集GC事件,对于这EventSource类的使用大家可以看下面给出的微软文档链接,这里不做过多介绍。

  • EventSource

  • EventListener
    我们来看一看如何使用EventListener类监听GC事件,代码如下所示:

using System.Diagnostics.Tracing;  // 开启GC事件监听  var gc = new GcStwMetricsCollector();  
// 创建一些对象  var array = Enumerable.Range(0, 1000).Select(s => (decimal)s).ToArray();  
// 手动执行GC  GC.Collect();  
Console.ReadLine();  public class GcStwMetricsCollector : EventListener  {  // GC关键字  private const int GC_KEYWORD = 0x0000001;  // 我们要关注的GC事件  private const int GCSuspendEEBegin = 9;  private const int GCRestartEEEnd = 3;  private EventSource? _eventSource;  public void Stop()  {  if (_eventSource == null)  return;  DisableEvents(_eventSource);  }  protected override void OnEventSourceCreated(EventSource eventSource)  {  _eventSource = eventSource;  // GC 事件在 Microsoft-Windows-DotNETRuntime 名称空间下   if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime"))  {  // 启用事件,事件级别为Informational, 只监听GC事件  EnableEvents(eventSource, EventLevel.Informational, (EventKeywords) (GC_KEYWORD));  }  }  private long _currentStwStartTime = 0;  protected override void OnEventWritten(EventWrittenEventArgs e)  {  switch (e.EventId)  {  // 冻结托管线程开始,记录当前时间  case GCSuspendEEBegin:  _currentStwStartTime = e.TimeStamp.Ticks;  break;  // 恢复托管线程结束,计算当前时间与冻结托管线程开始时间的差值  case GCRestartEEEnd:  if (_currentStwStartTime > 0)  {  var ms = TimeSpan.FromTicks(e.TimeStamp.Ticks - _currentStwStartTime).TotalMilliseconds;  _currentStwStartTime = 0;  // 输出结果  Console.WriteLine($"STW: {ms}ms");  }  break;  }  }  
}
折叠

运行结果:

STW: 0.2568ms

至于GC事件对应的枚举值,大家可以在我上文中给出的文档中找到。
c1c345225eac93d2f510288c27b4df81.png

.NET7新API

在实现这个需求时,我注意到.NET7有一个新的issue,直接提供了一个API,让我们可以获取到总的GC STW Time,我把重点的信息摘抄和翻译了一下。

背景和动机

今天我们已经在GetGCMemoryInfo 公开了获取GC处理时间和暂停时间的百分比值的API。
具体来说是通过GCMemoryInfo的PauseTimePercentage字段。
这个很有用,但是如果我只想要一个分子(即:程序运行以来总的GC暂停时间)。现在没有办法获取到。

API 提案

我建议在System.GC上添加一个下面这样的API:

TimeSpan System.GC.GetTotalPauseDuration()

它会返回GC总的暂停时间。

API 使用

TimeSpan start = System.GC.GetTotalPauseDuration();// ... Perform some work ...TimeSpan end= System.GC.GetTotalPauseDuration();
Console.WriteLine(end - start + " was spent pausing in GC");
我看到这个API已经和最新的.NET7预览版一起发布,我们下载最新的.NET7 SDK,然后把项目改成.NET7,来试试这个API,代码如下所示:
using System.Diagnostics.Tracing;  // 开启GC事件监听  var gc = new GcStwMetricsCollector();  
// 创建一些对象  var array = Enumerable.Range(0, 1000).Select(s => (decimal)s).ToArray();  
// 手动执行GC  GC.Collect();  
Console.WriteLine($"API STW:{GC.GetTotalPauseDuration().TotalMilliseconds}ms");  
Console.ReadLine();// 省略上文中一样的代码
运行结果:
API STW: 0.223ms
Event STW: 0.296ms

API统计的应该会更加准确,我们通过事件来获取多多少少有一点额外的开销,不过误差在可接受的范围内。

总结

上文中提到了两种方式来获取.NET GC STW Time,我们只需要稍加改造,就可以将STW监控的功能加入APM中,如下图表就是本地测试时采集的一些数据。
cad233ac3cf6ece5ab9778685000a40d.png
当然通过EventListener还可以实现更多的APM信息的采集,大家有兴趣也可以研究看看。

本文代码链接Github: https://github.com/InCerryGit/BlogCodes/tree/main/Get-GC-STW-Time

往期文章:
.NET性能优化-推荐使用Collections.Pooled(补充)
.NET性能优化-使用ValueStringBuilder拼接字符串
.NET性能优化-使用结构体替代类

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

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

相关文章

C语言试题136之打印出杨辉三角形(要求打印出 10 行如下图)

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:打印出杨辉三角形(要求打印…

【ArcGIS风暴】ArcGIS矢量数据分层设色后导出或裁剪后颜色分类丢失完美解决办法

在利用ArcGIS做土地利用现状图或者规划图时,事先费了好大劲把每个地类对应的图斑进行了符号化(用不同的颜色表示),后来把符号化好的数据导出,并进行加载,发现颜色分类完全丢失了,同样,在利用某个重点区域范围裁剪后,颜色变成了单一的颜色。 符号化成果: 导出后加载矢…

如何使用Cmder替换cmd

一、cmder介绍 cmder是一款Windows环境下非常简洁美观易用的cmd替代者,它支持了大部分的Linux命令。支持ssh连接linux,使用起来非常方便。比起cmd、powershell、conEmu,其界面美观简洁,功能强大。 二、下载地址 地址&#xff1a…

C语言试题137之画点

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:利用putpixel 画点。 2 、温…

Delphi WinExec ShellExec 用法介绍

2019独角兽企业重金招聘Python工程师标准>>> Delphi WinExec ShellExec 用法介绍 在Windows程序设计中WinAPI也为我们提供了类似的函数,它们就是WinExec()和ShellExecute(),下面就来讨论一下这两个函数的用法。 1)WinExec() 函数原型&#x…

各大主流编程语言性能PK,结果出乎意料

出品 | OSC开源社区(ID:oschina2013)“什么编程语言速度最快”,为了回答这个问题,The Benchmarks Game 专门面向主流编程语言设计了性能测试。测试的项目包括(可点击文末阅读原文查看详情)&…

【MapBox】5种地图(底图)样式自由切换附源码

文章目录 一、不同地图显示样式1. 卫星2. 浅色3. 深色4. 街道5. 户外二、完整源码一、不同地图显示样式 MapBox提供了5种不同形式的地图显示样式: 1. 卫星 2. 浅色

[转]vue项目中,main.js,App.vue,index.html如何调用

1、main.js是我们的入口文件,主要作用是初始化vue实例,并引入所需要的插件 2、App.vue是我们的主组件,所有页面都是在App.vue下进行切换的。其实你也可以理解为所有的路由也是App.vue的子组件。所以我将router标示为App.vue的子组件。 index…

C语言试题138之画椭圆

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:画椭圆 ellipse 2 、温馨提示…

光纤熔接过程详细说明

在我们实际的网络工作当中会遇到光纤的熔接,由于目前光纤熔接的工艺已经成熟完善,对于一根六芯光纤整个熔接过程需要2名工程师,大约需要花费1个小时的时间就可以完成。我们首先考虑的是为光纤线缆留出足够的长度来,多了好办&#…

Playwright之录制

前言前段时间看了大佬分享的关于Playwright.NET的文章感觉挺有意思,想要阅读点击:此处,然后跟随大佬的脚步,学习了一点自动化玩,其中有一个录制功能感觉挺好玩,下面就来简单看看介绍手动操作浏览器&#xf…

【MapBox】在地图上创建多个Marker点,设置鼠标经过提示信息,单击跳转到链接

本文讲述在MapBox地图上创建多个Point点,然后设置鼠标经过每个点提示信息,再让每个点鼠标点击跳转到指定的不同的链接地址。 任务描述: 显示MapBox地图添加Marker设置鼠标经过提示设置Marker单击链接效果展示: 点击Marker跳转到指定的链接地址。 源码赠送: <!DOCTYPE …

Timequest的波形窗口调出

在使用TIMEQUEST做时序约束的时候,波形是很直观的一个界面,但是在操作的时候顺手向下一拉,波形窗口就不见了, 再report timing的时候就这样了,只有summary,没有波形窗口了. 找了半天的的view等等菜单没找到怎么打开,最后将鼠标放在下图位置他又出现了 出现上下拉的标签向上拉就…

[转]vue-codemirror 代码编辑器

codemirror 是一个非常强大的代码编辑器插件&#xff0c;但官方并没有提供 vue 的支持版本&#xff0c;不过跟 vue 集成的步骤并不复杂&#xff0c;以下是具体实现 更多精彩 更多技术博客&#xff0c;请移步 IT人才终生实训与职业进阶平台 - 实训在线相关网址 Vue 官方插件库推…

C语言试题139之输入 3 个数 a,b,c,按大小顺序输出(利用指针)

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:输入 3 个数 a,b,c,按大小顺…

【ArcGIS Pro微课1000例】0001:Win7系统ArcGIS Pro2.5安装权威教程(附软件安装包下载)

ArcGIS Pro是ESRI桌面产品线的新秀,集很多新技术于一身,原生支持64位系统,Ribbon界面,支持二三维一体化等。可以与别的版本的ArcGIS软件共存。 文章目录 1. 系统环境配置2. 安装ArcGIS pro3. 打补丁,登录账户4. 安装中文5. ArcGIS pro 2.5下载地址1. 系统环境配置 ࿰

Maven发布工程到私服

所谓发布工程就是把工程打包成jar包&#xff0c;然后选择上传到私服的某个仓库里&#xff0c;然后其他人就可以在私服上的仓库中下载到你发布的工程。 简单介绍Nexus上自带的一些仓库&#xff1a; 如果想要发布工程是需要一个拥有发布权限的用户的&#xff0c;没有发布权限的游…

善用兵者,藏于无形,90 分钟深度讲解最佳推广价值作品

&#x1f4a1;提示本文带有极大的主观色彩&#xff0c;及不代表微软组织的可视化大赛观点&#xff0c;也不代表作者本人观点。全部解读均为这里的独到观点&#xff0c;任何解释错误与作者或大赛无关。没有作品文件下载&#xff0c;全文仅从外观推断和赏析整个结构。如果你已经被…

C语言试题140之输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:输入数组,最大的与第一个元…

【ArcGIS Pro微课1000例】0003:ArcGIS pro 2.5加载OSGB点云模型案例教程

Esri采用的spk i3s标准(Indexed 3D Scene),是Esri推出的开放标准。I3S标准作为开放的标准已经得到了市面上主流的倾斜摄影测量建模软件的支持,如Bentley的 ContextCapture(国内简称为Smart 3D)、Pix4D、Vricon,这些软件均支持基于I3S标准的数据格式SLPK的导出,生成的SLP…