当前位置:   article > 正文

PerfView专题 (第十二篇):对 C# 下的 SDK 类库进行监控(大结局)

perfview专题 (第十二篇)

一:背景

本篇是我们系列文章的最后一篇,前面的文章中大多是在 CLR Runtime 以及 OS 层面进行监控来发现各种可疑的程序问题,除了这两个层面,其实我们还可以对 SDK 中一些类进行洞察,比如说:

  1. ArrayPool

  2. Http

  3. Socket

  4. Task

更多资料可以看下:https://docs.microsoft.com/en-us/dotnet/core/diagnostics/well-known-event-providers

接下来就来个简单的抛砖引玉

二:如何洞察

1. ArrayPool 监控

之所以对 ArrayPool 感兴趣,主要还是因为在分析 Dump 的过程中,遇到过几起 LOH 碎片化问题,比如使用第三方模板生成引擎生成 Html 导致大量临时性 char[], byte[],终导致 LOH 破败不堪,所以最后给出的建议是使用这种池化ArrayPool,如果可以监控池的租借情况,那是不是挺好的?哈哈,还真有这样的 ETW,截图如下:

8e544215d6fd0aaa2eeccb266cb0049f.png

为了方便讲解,先上一段简单的测试代码:

  1. internal class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             var shared = ArrayPool<int>.Shared;
  6.             var rentedArray = shared.Rent(10);
  7.             for (int i = 0; i < 10; i++)
  8.             {
  9.                 rentedArray[i] = i + 1;
  10.             }
  11.             for (int j = 0; j < 10; j++)
  12.             {
  13.                 Console.WriteLine(rentedArray[j]);
  14.             }
  15.             shared.Return(rentedArray);
  16.             Console.ReadKey();
  17.         }
  18.     }

接下来启动 Perfview,在 Additional Providers 上输入:

*System.Buffers.ArrayPoolEventSource:::@StacksEnabled=true

然后开启 Start Collection 观察 Array 的租借情况,稍等片刻后,在 Event 中搜索 ArrayPool 可以看到相关的 ETW 事件,截图如下:

93b8480f3f68fc8aaeb34749bcef72d7.png

Rent 列的 bufferSize="16" 中可知,当前租借了一个 size=16 的数组。

HasStack="True" ThreadID="15,060" ProcessorNumber="10" bufferId="32,854,180" bufferSize="16" poolId="27,252,167" bucketId="-1"

因为开启了 Stack 功能,可以在 Time MSec 列上右键选择 Open Any Stacks,在弹窗中可以轻松找到这个 rent 所在的代码,截图如下:

69f14faaabf92fe5c60b6c8d38a65cd6.png

2. Http 监控

对 Http 的监控也是由于最近遇到了一个比较头疼的 dump 有感而发的,一个朋友的 dump 出现了 cpu 100% 的情况,我分析下来发现是程序在短时间内出现了大量的 Http Exception,进一步排查怀疑是 sdk 里面的异常,由于被吞了所以上层获取不到,也就找不到是第三方 sdk 哪里的代码块出的问题。

这里的找不到或者很难找到是在 WinDBG 场景下,其实借助 PerfView 还是比较好发现的,途径就是开启 System.Net.Http ETW 事件,它内置了 14 个,太强大了,截图如下:

cbd26741fc7f0d9ce42c0e7bce3f939c.png

为了方便讲述,先上一段测试代码。

  1. internal class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             for (int i = 0; i < 5; i++)
  6.             {
  7.                 GetString();
  8.             }
  9.             Console.ReadLine();
  10.         }
  11.         static async void GetString()
  12.         {
  13.             try
  14.             {
  15.                 HttpClient client = new HttpClient();
  16.                 var html = await client.GetStringAsync("https://cnblogs1.com");
  17.                 Console.WriteLine(html);
  18.             }
  19.             catch (Exception ex)
  20.             {
  21.                 Console.WriteLine(ex.Message);
  22.             }
  23.         }
  24.     }
2b80f9717080996bb13db18b98d948fe.png

这段代码会抛出异常,然后在 catch 中给吞掉了,因为抛了异常,就可以观察它的 RequestFailed 事件,然后找到对应的 RequestStart 事件,再观察它的调用栈即可。

接下来在 PerfView 中设置 *System.Net.Http:::@StacksEnabled=true,再开启收集按钮,稍等片刻点击 Event 面板,搜集 Http 事件,截图如下:

d95c18fc046b7df5911cc64adc0fa773.png

从面板中可以清晰的观察到当前有 5 个请求失败,并且还带了关联的 ActivityID, 接下来可以找 ActivityID=/#18920/1/29/ 对应的 Request/Start 事件。

c7c01a6e3621b878b9e6c82d16b4fe25.png

然后在 Time MSec 列上右键点击 Open Any Stacks 按钮,可以轻松的看到,那个 Request/Start 事件是 GetString() 方法触发的,截图如下:

3a7327e53c4835f5021e3e6c32975784.png

3. 总结

总的来说,在 .NET 调试领域,让 PerfView 适当的配合 WinDbg,真的可以 如虎添翼 ,好了,本系列就先写到这里,感谢朋友们对本系列的持续关注。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/115338
推荐阅读
相关标签
  

闽ICP备14008679号