AOT漫谈专题(第二篇): 如何对C# AOT轻量级APM监控

一:背景

1. 讲故事

上一篇我们聊到了如何调试.NET Native AOT 程序,这是研究一个未知领域知识的入口,这篇我们再来看下如何对 Native AOT 程序进行轻量级的APM监控,当然这里的轻量级更多的是对 AOT 中的coreclr内容的挖掘。

二:如何轻量级APM监控

1. 一个简单的例子

用一个不断的往内存中囤积数据的例子来演示吧,然后观察内存的趋势变化,参考代码如下:


    internal class Program
    {
        public static List<string> list = new List<string>();

        static void Main(string[] args)
        {
            Debugger.Break();

            Task.Run(() => { Run(); }).Wait();
        }

        static void Run()
        {
            for (int i = 0; i < 10000; i++)
            {
                list.Add(string.Join(", ", Enumerable.Range(0, 20000)));
                Thread.Sleep(1);
                Console.WriteLine($"i={i}");
            }
        }
    }

这里要注意的是,AOT在 ilc 编译的过程中会采用摇树优化,言外之意就是 eventpipe跟踪组件 默认是不加入的,这个组件的源码在 src\native\eventpipe 目录下,主要是采用 ipc 的方式与接收者进行通讯。

如果有点懵的话可以简单的理解成这东西是托管版的ETW,msdn 上也给了一张对比图,参考如下:

说了这么多,言外之意就是要把 eventpipe 保留,方式就是在 csproj 中配置 EventSourceSupport =true 即可,参考如下:


<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<PublishAot>true</PublishAot>
		<InvariantGlobalization>true</InvariantGlobalization>
		<EventSourceSupport>true</EventSourceSupport>
	</PropertyGroup>

</Project>

接下来用 dotnet cli 进行 public 发布,参考如下:


dotnet publish -r win-x64 -c Debug  -o D:\testdump

程序启动好之后,接下来用dotnet-counter来洞察一下程序的托管堆,CPU 等各种指标,安装方式可以参考链接:https://learn.microsoft.com/zh-cn/dotnet/core/diagnostics/dotnet-counters


PS C:\Users\Administrator\Desktop> dotnet-counters monitor -n Example_21_1

从上图中我们确实也真真切切的看到了进程的各个指标,有些朋友可能会好奇,如果我没开 EventPipe还能挖到这些信息吗?这当然是可以的,不过这就需要你对 coreclr 底层有一定的了解度了。

2. 如何用windbg去挖

首先要知道的是sos 在 aot 中用不了的,但用不了不代表我们没办法,因为 sos 也是从 coreclr 中挖取的数据,那为什么我就不能自己去挖呢?

  1. 如何挖托管堆数据

sos 是在coreclr 的 gc_heap::generation_table 全局数组中挖取的数据,言外之意我也可以手工的去挖,然后拼凑成托管堆 ,参考如下:


0:009> dx -r1 (*((Example_21_1!WKS::generation (*)[5])0x7ff6fa99ca90))
(*((Example_21_1!WKS::generation (*)[5])0x7ff6fa99ca90))                 [Type: WKS::generation [5]]
    [0]              [Type: WKS::generation]
    [1]              [Type: WKS::generation]
    [2]              [Type: WKS::generation]
    [3]              [Type: WKS::generation]
    [4]              [Type: WKS::generation]

这个数组就对应着 0代,1代,2代,LOH代,POH代 等数据。

  1. 如何知道当前机器的内存总量和CPU核心数

这个数据在dump分析过程中非常重要,它可以表示当前机器的robust能力,这些数据在 coreclr 的 g_SystemInfototal_physical_mem 全局变量中,参考如下:


0:009> x Example_21_1!WKS::gc_heap::total_physical_mem
00007ff6`fa9ac1b0 Example_21_1!WKS::gc_heap::total_physical_mem = 0x00000007`f7bbd000

0:009> ? 0x00000007`f7bbd000 /0n1024/0n1024/0n1024
Evaluate expression: 31 = 00000000`0000001f

0:009> dt Example_21_1!g_SystemInfo
   +0x000 dwNumberOfProcessors : 0xc
   +0x004 dwPageSize       : 0x1000
   +0x008 dwAllocationGranularity : 0x10000

可以看到当前机器的内存总量是 31G(32G),同时机器的CPU=12。

  1. 如何挖掘GC触发信息

捕获gc的触发可以有效的获取gc的触发代,触发原因,以及当前的托管堆静态和动态阈值情况,对我们洞察程序非常有帮助,那如何捕获呢?可以对gc触发的必经之路上下一个断点即可,比如:bp Example_21_1!WKS::gc_heap::gc1


0:010> bp Example_21_1!WKS::gc_heap::gc1 
0:010> g
Breakpoint 0 hit
Example_21_1!WKS::gc_heap::gc1:
00007ff7`e268cd20 488bc4          mov     rax,rsp
0:006> k 5
 # Child-SP          RetAddr               Call Site
00 0000001d`6c6febb8 00007ff7`e268ccac     Example_21_1!WKS::gc_heap::gc1 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 22250] 
01 0000001d`6c6febc0 00007ff7`e26742e0     Example_21_1!WKS::gc_heap::garbage_collect+0x77c [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 24332] 
02 0000001d`6c6fec70 00007ff7`e26a5a8a     Example_21_1!WKS::GCHeap::GarbageCollectGeneration+0x300 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 50529] 
03 0000001d`6c6fecd0 00007ff7`e2672d84     Example_21_1!WKS::gc_heap::trigger_gc_for_alloc+0x5a [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 18906] 
04 (Inline Function) --------`--------     Example_21_1!WKS::gc_heap::try_allocate_more_space+0x14e [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 19048] 
...

接下来洞察内部的 gc_heap::settings 结构,信息如下:


0:006> dt Example_21_1!WKS::gc_heap::settings 00007ff7`e2c46fb0
   +0x000 gc_index         : Volatile<unsigned __int64>
   +0x008 condemned_generation : 0n0
   +0x00c promotion        : 0n0
   +0x010 compaction       : 0n1
   +0x014 loh_compaction   : 0n0
   +0x018 heap_expansion   : 0n0
   +0x01c concurrent       : 0
   +0x020 demotion         : 0n0
   +0x024 card_bundles     : 0n1
   +0x028 gen0_reduction_count : 0n0
   +0x02c should_lock_elevation : 0n0
   +0x030 elevation_locked_count : 0n0
   +0x034 elevation_reduced : 0n0
   +0x038 minimal_gc       : 0n0
   +0x03c reason           : 0 ( reason_alloc_soh )
   +0x040 pause_mode       : 1 ( pause_interactive )
   +0x044 found_finalizers : 0n0
   +0x048 background_p     : 0n0
   +0x04c b_state          : 0 ( bgc_not_in_process )
   +0x050 entry_memory_load : 0x30
   +0x058 entry_available_physical_mem : 0x00000004`1a660000
   +0x060 exit_memory_load : 0

0:006> dx -r1 (*((Example_21_1!Volatile<unsigned __int64> *)0x7ff7e2c46fb0))
(*((Example_21_1!Volatile<unsigned __int64> *)0x7ff7e2c46fb0))                 [Type: Volatile<unsigned __int64>]
    [+0x000] m_val            : 0xd [Type: unsigned __int64]

0:006> ? 0x41a660000/0n1024/0n1024/0n1024
Evaluate expression: 16 = 00000000`00000010

从上面的输出中可以看到当前GC的信息特别多:0xd次触发,并且是压缩式的回收,触发的是 0代,原因是代满了,当前机器还可使用的内存是 16G。

三:总结

虽然 .NET AOT 越来越成熟,但目前还是不能对 gcheap 进行sos级的分析,暂时只能手工的挖掘整理,不过我相信在 .NET10 或者 11 上应该能够得到完整的支持,毕竟这势不可挡!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

工业物联网关-ModbusTCP

Modbus-TCP模式把网关视作Modbus从端设备&#xff0c;主端设备可以通过Modbus-TCP协议访问网关上所有终端设备。用户可以自定义多条通道&#xff0c;每条通道可以配置为TCP Server或者TCP Slave。注意&#xff0c;该模式需要指定采集通道&#xff0c;采集通道可以是串口和网口通…

linux 下 verilog 简明开发环境附简单实例

author: hjjdebug date: 2024年 10月 12日 星期六 10:34:13 CST descripton: linux 下 verilog 简明开发环境附简单实例 甲: 安装软件 1. sudo apt install iverilog 该包verilog 源代码的编译器iverilog&#xff0c;其输出是可执行的仿真文件格式vvp格式 它可以检查源代码中…

跟踪一切学习笔记2024

目录 Track-Anything 多目标跟踪分割 masa 多目标检测跟踪: omnimotion iKUN Track-Anything 交互式,选择多个要跟踪的物体,最后是分割 多目标跟踪分割 https://github.com/gaomingqi/Track-Anything masa 多目标检测跟踪:

单臂路由实现vlan间互访

划分vlan 可以隔离广播域,但vlan 之间无法通信。既能隔离广播域,防止广播风暴的发生,又能实现vlan 之间的通信,就需要用到网络层的路由器,可以通过路由器,以单臂路由的方式来实现vlan 之间的通信。 以下是在神州交换机和路由器上实现单臂路由实现 VLAN 间互访的配置代码示…

Sentinel最全笔记,详细使用步骤教程清单

一、Sentinel的基本功能 1、流量控制 流量控制在网络传输中是一个常用的概念&#xff0c;它用于调整网络包的发送数据。然而&#xff0c;从系统稳定性角度考虑&#xff0c;在处理请求的速度上&#xff0c;也有非常多的讲究。任意时间到来的请求往往是随机不可控的&#xff0c;…

光伏项目难管理的问题如何解决?

1.数字化管理平台的应用 数字化是当前解决光伏项目管理难题的关键手段之一。通过建立统一的数字化管理平台&#xff0c;可以实现对光伏电站的远程监控、数据分析、故障预警及运维调度等功能。这类平台通常集成有智能算法&#xff0c;能够实时分析电站运行数据&#xff0c;及时…

Flink 批作业如何在 Master 节点出错重启后恢复执行进度?

摘要&#xff1a;本文撰写自阿里云研发工程师李俊睿&#xff08;昕程&#xff09;&#xff0c;主要介绍 Flink 1.20 版本中引入了批作业在 JM failover 后的进度恢复功能。主要分为以下四个内容&#xff1a; 背景解决思路使用效果如何启用 一、背景 在 Flink 1.20 版本之前&am…

LeetCode讲解篇之2320. 统计放置房子的方式数

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们首先发现一个规律街道两侧是否放置房子是独立的&#xff0c;即放置房子的方式数 一侧放置房子的方式数 * 另一侧放置房子的方案数 一侧放置房子的方式数的二次方 对于一侧[0, i]范围内地块放置房子的方式…

用无人机视角,打开哀牢山!

哀牢山危险且神秘&#xff0c;使用无人机进行探索可以极大地提高安全性和效率。通过无人机的关键性能&#xff0c;将哀牢山的情况记录并传输出来 一、高清摄像与图像传输 高清摄像头&#xff1a;无人机通常搭载高分辨率的摄像头&#xff0c;能够捕捉到哀牢山细腻的自然景观和…

opencv外接矩形cv2.boundingRect和cv2.minAreaRect区别

在OpenCV中&#xff0c;cv2.boundingRect和cv2.minAreaRect是两个用于获取图像中形状边界的函数&#xff0c;但它们在功能和返回结果上有所不同。以下是两者的详细区别&#xff1a; 1. cv2.boundingRect 和 cv2.minAreaRect 功能描述 cv2.boundingRect 主要是用来计算图像轮廓…

第二十三篇:网络拥塞了,TCP/IP如何解决的?

一.显示拥塞通知 当发生网络拥塞时&#xff0c;发送主机应该减少数据包的发送量。作为IP上层协议&#xff0c;TCP虽然也能控制网络拥塞&#xff0c;不过它是通过数据包的实际损坏情况来判断是否发生拥塞。然而这种方法不能在数据包损坏之前减少数据包的发送量。 为了解决这个…

JAVA自动化测试TestNG框架

1.TestNG简介 JAVA自动化测试最重要的基石。官网&#xff1a;https://testng.org 使用注解来管理我们的测试用例。 发现测试用例 执行测试用例 判断测试用例 生成测试报告 2.创建Maven工程 2.1创建一个maven工程 2.2设置maven信息 2.3设置JDK信息 2.4引入testng依赖 <dep…

springboot001基于SpringBoot的在线拍卖系统(论文+源码)_kaic

医护人员排班系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了医护人员排班系统的开发全过程。通过分析医护人员排班系统管理的不足&#xff0c;创建了一个计算机管理医护人员排班系统的方案。文章介绍了医…

腾讯云视立方Electron 相关问题

安装相关 trtc-electron-sdk 是否兼容官方 Electron v12.0.1 版本? 兼容的&#xff0c;trtc-electron-sdk 没有特别依赖 elecron 自身的 SDK&#xff0c;所以没有相关的版本依赖。 Electron 下载慢甚至卡住不动&#xff1f; 当开始下载tmp-3320-1-SHASUMS256.txt-6.1.9文件…

JDK17常用新特性

目前国内大部分开发人员都是在使用jdk8&#xff0c;甚至是jdk6&#xff0c;但是随着jdk的更新迭代&#xff0c;jdk8我觉得可能就会慢慢的淡出舞台&#xff0c;随着目前主流框架最新版推出明确说明了不再支持jdk8&#xff0c;也促使我不得不抓紧学习了解一波jdk17的新特性&#…

PDSCH DMRS(解调参考信号)简述

文章目录 PDSCH DMRS&#xff08;解调参考信号&#xff09;简述基本问题例子1. 层数和无数据的DMRS CDM组数量资源元素映射 用户设备假设 PDSCH DMRS&#xff08;解调参考信号&#xff09;简述 这是用来做什么的&#xff1f; 这是一个专门用于解码PDSCH的下行无线信道估计的物理…

【Java学习笔记】多线程

当我们在饭店聚餐时&#xff0c;多人同时吃一道菜的时候很容易发生争抢。例如&#xff0c;上了一道好菜&#xff0c;两个人同时夹这道菜&#xff0c;一人刚伸出筷子&#xff0c;结果伸到的时候菜已经被夹走了。为了避免这种现象&#xff0c;必须等一人 夹完一口后&#xff0c;另…

elementui中el-radio-group内容过长溢出问题

鼠标悬停显示文字 <template> <el-radio-group class"fixed-width-radio-group" v-model"continueruleForm.category" size"mini" fill"#2f54eb" color"#2f54eb" > <el-radio-button label"pr…

Django学习笔记之Django基础学习

Django笔记 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录…

ZYNQ使用XGPIO驱动外设模块(前半部分)

目录 目录 一、新建BD文档&#xff0c;添加ZYNQ处理器 1.BD文档: 2.在Vivado中&#xff0c;BD文件的生成过程通常包括以下步骤&#xff1a; 1)什么是Tcl Console: 3.PL部分是FPGA可编程逻辑部分&#xff0c;它提供了丰富的IO资源&#xff0c;可以用于实现各种硬件接口和功…