一:背景

1. 讲故事

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

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

二:PerfView 分析

1. 测试案例

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


// 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 句柄泄露,参考代码如下:


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 真的是一对好搭档,优势互补。

PerfView专题 (第十三篇):洞察 .NET程序 的非托管句柄泄露的更多相关文章

  1. PerfView专题 (第七篇):如何洞察触发 GC 的 C# 代码?

    一:背景 上一篇我们聊到了如何用 PerfView 洞察 GC 的变化,但总感觉还缺了点什么? 对,就是要跟踪到底是什么代码触发了 GC,这对我们分析由于 GC 导致的 CPU 爆高有非常大的参考价值 ...

  2. PerfView专题 (第十一篇):使用 Diff 功能洞察 C# 内存泄漏增量

    一:背景 去年 GC架构师 Maoni 在 (2021 .NET 开发者大会) [https://ke.segmentfault.com/course/1650000041122988/section ...

  3. PerfView专题 (第三篇):如何寻找 C# 中的 VirtualAlloc 内存泄漏

    一:背景 上一篇我们聊到了如何用 PerfView 去侦察 NTHeap 的内存泄漏,这种内存泄漏往往是用 C 的 malloc 或者 C++ 的 new 分配而不释放所造成的,这一篇我们来聊一下由 ...

  4. PerfView专题 (第四篇):如何寻找 C# 中程序集泄漏

    一:背景 前两篇我们都聊到了非托管内存泄漏,一个是 HeapAlloc ,一个是 VirtualAlloc,除了这两种泄漏之外还存在其他渠道的内存泄漏,比如程序集泄漏,这一篇我们就来聊一聊. 二: 程 ...

  5. PerfView专题 (第五篇):如何寻找 C# 托管内存泄漏

    一:背景 前几篇我们聊的都是 非托管内存泄漏,这一篇我们再看下如何用 PerfView 来排查 托管内存泄漏 ,其实 托管内存泄漏 比较好排查,尤其是用 WinDbg,毕竟C#是带有丰富的元数据,不像 ...

  6. 托管程序调用非托管dll问题总结

    托管程序Visual Basic.net, 非托管DLL标准C++程序(使用VC++编译) 函数调用定义 第一种写法: <DllImportAttribute("XXX.dll&quo ...

  7. PerfView专题 (第六篇):如何洞察 C# 中 GC 的变化

    一:背景 在洞察 GC 方面,我觉得市面上没有任何一款工具可以和 PerfView 相提并论,这也是为什么我会在 WinDbg 之外还要学习这么一款工具的原因,这篇我们先简单聊聊 PerfView 到 ...

  8. PerfView专题 (第八篇):洞察 C# 内存泄漏之寻找静态变量名和GC模式

    一:背景 这篇我们来聊一下 PerfView 在协助 WinDbg 分析 Dump 过程中的两个超实用技巧,可能会帮助我们快速定位最后的问题,主要有如下两块: 洞察内存泄漏中的静态大集合变量名. 验证 ...

  9. PerfView专题 (第十篇):洞察 C# 终结队列引发的内存泄漏

    一:背景 C# 程序内存泄漏的诱发因素有很多,但从顶层原理上来说,就是该销毁的 用户根 对象没有被销毁,从而导致内存中意料之外的对象无限堆积,导致内存暴涨,最终崩溃,这其中的一个用户根就是 终结器队列 ...

  10. 将WinForm程序(含多个非托管Dll)合并成一个exe的方法

    原文:将WinForm程序(含多个非托管Dll)合并成一个exe的方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. ILMerge能把托管dl ...

随机推荐

  1. Qt5.9 UI设计(七)——统一样式设计

    前言 前面已经将UI设计部分实现,各页面也做了最简单的设计,本章介绍一下qss样式的使用.样式设计最终的显示效果如下图: 操作步骤 将stylesheet.qss 样式文件添加进工程 styleshe ...

  2. 20130625-关于mac配置android cocos2dx

    1.下载cocos2dx  ndk  eclipse http://developer.android.com/tools/sdk/ndk/index.html 2.cocos2dx文件中找到crea ...

  3. Awesome GPT 来了!

    大家好!我是韩老师. GPT, ChatGPT, OpenAI, LLM(大语言模型)等等技术的出现与应用,改变了许多的行业和人. 长期来看,类 GPT 的技术会对整个世界有着持续的改变. 我们几乎每 ...

  4. javasec(二)class文件结构

    这篇文章介绍java的class文件结构. 深入理解Java虚拟机(类文件结构) 我们所编写的每一行代码,要在机器上运行最终都需要编译成二进制的机器码 CPU 才能识别.但是由于虚拟机的存在,屏蔽了操 ...

  5. Hystrix 如何在不引入 Archaius 的前提下实现动态配置更新

    Hystrix 简介 Hystrix 是 Netflix 开源的一个限流熔断降级组件,防止依赖服务发生错误后,将调用方的服务拖垮.这里对 Hystrix 本身不做过多介绍. Hystrix 目前处于维 ...

  6. Python argparse参数管理学习笔记1

    1.前言 最近尝试学习使用argparse进行参数管理,顺便改善一下我那丝毫都不专业的.简单粗暴的代码习惯. argparse模块可以让人轻松地编写用户友好地命令行接口,并且还能够自动生成帮助与使用手 ...

  7. Linux grep命令详细教程

    [本文出自天外归云的博客园] 简介 Linux grep命令是一种非常常用的文本搜索工具,它可以在给定的文件中搜索匹配的字符串,并输出匹配的行.grep是全称"global search r ...

  8. lombok版本报错问题java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed module

    lombok版本报错问题 记录一个项目部署时遇到的问题,我本地采用的JDK8的版本,然后我的服务器采用的是JDK17,然后在用maven进行打包的时候,发现package失败. 复现 我在本地采用的l ...

  9. 如何实现一个sync.Once

    sync.Once 是 golang里用来实现单例的同步原语.Once 常常用来初始化单例资源, 或者并发访问只需初始化一次的共享资源,或者在测试的时候初始化一次测试资源. 单例,就是某个资源或者对象 ...

  10. 小米商城主页展示HTML+CSS

    大佬们呀,花了好几天的时间总算是看着页面展示可以了,求赐教! 小米商城主页,对大佬来说肯定简单爆了,我抄写了好久呀,总是有一点点的小问题,还搞不明白 主要是一个静态的小米商城页面,HTML前端代码不复 ...