当前位置:首页 >探索 >PerfView洞察 .NET程序 非托管句柄泄露 为了让事件产生的更少

PerfView洞察 .NET程序 非托管句柄泄露 为了让事件产生的更少

2024-06-29 07:03:35 [百科] 来源:避面尹邢网

PerfView洞察 .NET程序 非托管句柄泄露

作者:一线码农聊技术 开发 前端 通过这个案例可以看到 PerfView 的洞察最大好处就是无侵入性,WinDbg 和 Perfview 真的序非泄露是一对好搭档,优势互补。托管

一:背景

1. 讲故事

前几天写了一篇 如何洞察 .NET程序 非托管句柄泄露 的句柄文章,文中使用 WinDbg 的洞察 !htrace 命令实现了句柄泄露的洞察,在文末我也说了,序非泄露WinDbg 是托管以侵入式的方式解决了这个问题,在生产环境中大多数情况下是句柄不能走附加进程的模式,所以这也是洞察它最大的局限性。

那如何以非侵入的序非泄露方式解决这个问题呢?这就是本篇讨论的重点,对,托管就是句柄用 CLR 团队 鼎力推荐的 Perfview 来解决这个问题,哈哈,洞察是序非泄露我昨天看文档无意发现的 😁😁😁。

PerfView洞察 .NET程序 非托管句柄泄露 为了让事件产生的更少

二:PerfView 分析

1. 测试案例

还是托管用那一篇文章的例子,让 C# 和 C++ 交互的时候产生句柄泄露, C++ 代码如下:

PerfView洞察 .NET程序 非托管句柄泄露 为了让事件产生的更少

// Example_20_1_5.cpp : This file contains the 'main' function. Program execution begins and ends there.//extern "C"{  _declspec(dllexport) void CSharpCreateEvent();}#include "iostream"#include <Windows.h>using namespace std;void CSharpCreateEvent(){  HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); printf("\nEvent句柄值: %#08x ", hEvent);}

在 C# 中我用 Task 的形式调用 CSharpCreateEvent 函数来产生 Event 句柄泄露,参考代码如下:

PerfView洞察 .NET程序 非托管句柄泄露 为了让事件产生的更少

internal class Program    {         [DllImport("Example_20_1_5", CallingConvention = CallingConvention.Cdecl)]        extern static void CSharpCreateEvent();        static void Main(string[] args)        {             try            {                 while (true)                {                     Task.Run(() =>                    {                         CSharpCreateEvent();                    });                    Thread.Sleep(10);                }            }            catch (Exception ex)            {                 Console.WriteLine(ex.Message);            }            Console.ReadLine();        }    }

2. Handle 分配监控

在 perfview 中可以开启内核级别的 OS Handle ETW事件 来进行分配和释放监控,用 +1 和 -1 表示,为了让事件产生的更少,在 Focus process 中指定 Example_20_1_4.exe ,并且选中 Handle 复选框,截图如下:

图片图片

如果嫌面板太麻烦,可以使用 /KernelEvents:Handle,Default 命令即可,完整的 Command 命令如下:

PerfView.exe  "/DataFile:PerfViewData.etl" /BufferSizeMB:256 /StackCompression /CircularMB:500 /KernelEvents:Handle,Default /NoGui /FocusProcess:"Example_20_1_4.exe" /NoNGenRundown collect

接下来点击 Start Collection 开启收集,收集一会之后点击 Stop Collection,生成好 Zip 之后选择 Advanced -> Windows Handle Ref Count Stacks 选项,在弹出面板中选择我们的 Example_20_1_4 程序,删除 GroupPats 分组信息,处理后的截图如下:

图片图片

从上面的面板信息的 Handle Type Event 来看,当前有 5445 个 Event 事件没有被 Close,原来是 Event事件 的泄露哈,接下来在右键面板中选择 Goto -> Item in Callers 选项可以看到每一个 Event 的详细列表。

图片图片

最后就是抽选其中几个,观察到底是什么代码创建的 Event ?截图如下:

图片图片

仔细观察面板信息,可以清楚的看到,原来是 Main 函数中有一个匿名方法,它在内部调用了 Example_20_1_5!CSharpCreateEvent 方法来创建句柄。

到这里就真相大白了。

三:总结

通过这个案例可以看到 PerfView 的最大好处就是无侵入性,WinDbg 和 Perfview 真的是一对好搭档,优势互补。

责任编辑:武晓燕 来源: 一线码农聊技术 .NET程序WinDbgPerfview

(责任编辑:百科)

    推荐文章
    热点阅读