首页 > 系统相关 >PerfView专题 (第十一篇):使用 Diff 功能洞察 C# 内存泄漏增量

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

时间:2022-08-25 17:55:08浏览次数:91  
标签:泄漏 dump C# PerfView 第十一篇 static 内存 增量

一:背景

去年 GC架构师 Maoni 在 (2021 .NET 开发者大会)

[https://ke.segmentfault.com/course/1650000041122988/section/1500000041123017] 上演示过 PerfView 的 Diff 功能来寻找内存增量,个人感觉这个功能非常不错,简单省事,所以这里就整合到 PerfView 专题中,分享一下给大家。

二:洞察内存增量

1. 什么是内存增量

其实非常好理解,就是当你的程序出现了内存泄漏,你可以在程序内存增长的过程中截取两个 dump 文件,然后通过 PerfView 观察其中的内存增量是什么? 帮助我们快速找出可能被泄漏的对象。

当然你用 WinDBG 的话也是没有问题的,只不过需要用肉眼扫一下而已,接下来举两个例子说明一下。

2. 静态集合的内存泄漏

很多 dump 的内存泄漏,源自于里面的某一个 static 变量无限堆积所致,为了方便说明,先上一段测试代码。


    internal class Program
    {
        static void Main(string[] args)
        {
            Task.Run(RunTest);
            Console.ReadLine();
        }

        public static List<string> my_big_list = new List<string>();

        static void RunTest()
        {
            for (int i = 0; i < 50000; i++)
            {
                my_big_list.Add(string.Join(",", Enumerable.Range(0, 10000)));
                Console.WriteLine(i);
            }
        }
    }

接下来在程序的运行过程中,我们分别截取两个 dump 文件, 点击菜单栏的 Memory -> Take Heap Snapshot 按钮,在 Filter 中搜索需要采集的进程,然后点击 Dump GC Heap 即可,参考如下图:

稍等片刻,你就会看到两个 gcdump 文件,这个和普通的 dump 是不一样的,算是 PerfView 专用的轻量级 dump 文件,截图如下:

接下来点击两个 gcdump 中的 Heap Stacks,对比 inc% 列后发现,内存都被一个叫 my_big_list 变量给吃掉了,前者的count为 10509, 后者是 15172,截图如下:

虽然肉眼可以简单观察,但这里可以使用专业的 Diff 功能,让 PerfView 帮我洞察 栈 的总体增量差异,点击菜单栏中的 Diff -> With Baseline: Heap Stacks [.....] 按钮,即让本 gcdump 和另一个 gcdump 做比较,截图如下:

不过要注意的是,这两个窗口一定要打开,这个是比较坑的,哈哈,接下来就会看到如下图:

从图中可以清晰的看到,这两个 dump 的增量主要来自于 my_big_list 集合,往细处说就是 string 增长了 4663 个。

3. 事件event泄漏

我们再看一个事件泄漏的例子,参考如下代码:


    // event 泄漏
    class Program
    {
        static event Action TestEvent;

        static void Main(string[] args)
        {
            var memory = new TestAction();

            //handle 泄漏
            for (int i = 0; i < int.MaxValue; i++)
            {
                TestEvent += memory.Run;

                if (i % 500 == 0)
                {
                    Console.WriteLine(i);
                }
            }

            Console.ReadLine();
        }

        public static void OnTestEvent()
        {
            if (TestEvent != null)
            {
                TestEvent();
            }
            else
            {
                Console.WriteLine("Test Event is null");
            }
        }

        class TestAction
        {
            public void Run()
            {
                Console.WriteLine("TestAction Run.");
            }
        }
    }

将程序运行起来,用 Process Explorer 抓两个 dump 文件下来,然后点击 Memory -> Take Heap Snapshot From Dump 按钮,截图如下:

在弹出的对话框中设置需要提取的 dump 文件,稍等片刻就会生成如下两个 gcdump 文件,截图如下:

接下来将两个 gcdump 都打开,发现内存都被程序中的一个叫 TestEvent 占用了,如下图所示:

接下来就可以使用 Diff 对比功能了,可以观察到,TestEvent 下面的 Action 增量了将近 700w 个,截图如下:

这里稍微说一下,为什么会增量 700w 的 Action,这主要是因为 event 是一个多播委托,内部有一个 Action 集合,也正是这个 Action 集合 在无限膨胀。

标签:泄漏,dump,C#,PerfView,第十一篇,static,内存,增量
From: https://www.cnblogs.com/huangxincheng/p/16625160.html

相关文章

  • 阅读《计算机图形学编程(使用OpenGL和C++)》8 - 纹理贴图
    纹理贴图就是将图片贴到模型上,让模型看起来更真实。纹理贴图非常重要,因此硬件也为它提供了支持,使得它具备了实现实时的照片级真实感的超高性能。纹理单元是专为纹理设计的......
  • 【Vue基础】provide和inject 依赖与注入
    Vue组件通信provide和inject,注入使用场景,祖先组件向下层所有组件注入,无论层级多深,子组件均能接收来自祖先组件。某个模块由根组件内统一管理子组件内的状态。类型prov......
  • 反射-Class对象功能概述以及获取Field
    Class对象功能概述1、获取成员变量们:Field[]getFields():获取所有public修饰的成员变量FieldgetField(Stringname):获取指定名称的public修饰的成员变量 Field[]g......
  • cracker
    Crackermayreferto:Cracker(food),atypeofbiscuit,usuallysaltedorsavouryCracker,anpetrochemicalindustrycomponentusedforcracking.Inpetroche......
  • 集合.Collection体系集合
    Collection父接口特点:代表一组任意类型的对象,无序,无下标,不能重复方法:booleanadd(Objectobj);添加一个对象booleanaddAll(Collectionc);将一个集合中的所有对象......
  • 实战 ElasticSearch
    一、基础知识你会如何处理实时或准实时数据流?在大数据时代,有很多方案可以帮助你完成这项任务。接下来,我将通过一个系列的教程,我将利用Storm、Kafka、ElasticSearch逐步......
  • crack
    Crackfrequentlyrefersto:Crack,afractureordiscontinuationinabodyCrack,ingeology,afracture(geology)inarockCrack,shortforcrackcocaine,t......
  • react 二级路由嵌套
    嵌套路由之后,静态文静路径错误,更改webpack 打包output输出根目录,publicPath:'/',二级路由刷新之后白屏,在首页模板文件中路径前加  /,   ......
  • TC判断用户对某个对象是否有更改的权限
    /** *获取是否有更改的权限 *@return */ publicStringgetCanChangeString(){ Stringtype=""; Stringproperty=""; try{ type=target.getPropert......
  • Caused by: java.lang.UnsupportedClassVersionError: com/hfplm/handler/HFEBOMation
    Causedby:java.lang.UnsupportedClassVersionError:com/hfplm/handler/HFEBOMationHandlerhasbeencompiledbyamorerecentversionoftheJavaRuntime(classf......