一:背景

内存泄漏 的系列问题中,有一类问题是 内存碎片化 导致的,而且这种更容易发生在 LOH 上,因为它默认不开启 对象压缩,一般遇到这种情况,优先让朋友执行下面的代码应急。


GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();

后续再研究问题根源,这篇我们就来聊一聊如何用 PerfView 神器帮助我们寻找 内存碎片化 的根源。

二:碎片化洞察

1. WinDbg 的局限

为了方便讲述,先上一段造成 LOH内存碎片化 的测试代码。


internal class Program
{
static void Main(string[] args)
{
Test(); Console.ReadLine();
} public static List<byte[]> list = new List<byte[]>(); static void Test()
{
for (int i = 0; i < 50000; i++)
{
if (i % 2 == 0)
{
list.Add(new byte[85000 * 2]);
list[i] = null;
}
else
{
list.Add(new byte[85000]);
}
} Console.WriteLine("5w 数据插入完毕!");
}
}

代码逻辑非常简单,就是间隔释放其中的 byte[] 对象,让 Free 和 Live 对象成交错状, 可以用 WinDbg 观察如下:


0:009> !dumpheap
Address MT Size
...
00000000f0cd6028 000000000050ff60 170088 Free
00000000f0cff890 00007ffdb4a25490 85024
00000000f0d144b0 000000000050ff60 170088 Free
00000000f0d3dd18 00007ffdb4a25490 85024
00000000f0d52938 000000000050ff60 170088 Free
00000000f0d7c1a0 00007ffdb4a25490 85024
00000000f0d90dc0 000000000050ff60 170088 Free
00000000f0dba628 00007ffdb4a25490 85024
00000000f0dcf248 000000000050ff60 170088 Free
00000000f0df8ab0 00007ffdb4a25490 85024
00000000f0e0d6d0 000000000050ff60 170088 Free
00000000f0e36f38 00007ffdb4a25490 85024
00000000f0e4bb58 000000000050ff60 170088 Free
00000000f0e753c0 00007ffdb4a25490 85024
00000000f0e89fe0 000000000050ff60 170088 Free
00000000f0eb3848 00007ffdb4a25490 85024
00000000f0ec8468 000000000050ff60 170088 Free
00000000f0ef1cd0 00007ffdb4a25490 85024
00000000f0f068f0 000000000050ff60 170088 Free
00000000f0f30158 00007ffdb4a25490 85024
00000000f0f44d78 000000000050ff60 170088 Free
...

虽然用 WinDBG 可以轻松找出,但这里有一个非常大的局限,就是你不知道 Free 对象生前是什么东西,往往这时候就只能用 db,dc,du 看内存地址,在无计可施的情况下, PerfView 就可以大显威龙了。

2. PerfView 洞察

接下来我们打开PerfView,采用默认设置启动收集,稍等之后,点击 Memory -> GCStats 项,观察 LOH Frag % 列,如下图所示:

从图中的 LOH Frag % 列可以看出碎片化确实蛮高的,接下来我们就是找 Free 块生前是什么东西,如果能记录到 Free 生成是由谁分配的那该有多好呀!!!

哈哈,在 PerfView 中还真有这么一个视图叫 Gen 2 Object Deaths Stacks,如下图所示:

从名字上就能看到,这个视图记录的是 LOH 上那些已经死亡对象的生前 Stack,当然了,这是按权重计算的,如果是 Event 模式产生的就好了,那会记录所有的对象分配。

接下来双击 Gen 2 Object Deaths Stacks 再选中我们的应用程序,可以看到权重占比最高的是 System.Byte[] 对象,如下图所示:

接下来右键点击 Goto -> Goto Item in Callers 按钮,可以看到占比最高的是 Program.Test() 分配所致,高达 9396 个,如下图所示:

接下来就是调研 Program.Test() 方法,找出最后被 Free 的原因, 这就是 PerfView 和 WinDbg 双剑合璧的威力。

PerfView专题 (第九篇):洞察 C# 中的 LOH 内存碎片化的更多相关文章

  1. Egret入门学习日记 --- 第九篇(书中 2.7~2.8节 内容)

    第九篇(书中 2.7~2.8节 内容) 昨天记录到了 2.6节 ,那么今天就从 2.7节 开始. 这个 2.7节 有7个小段,有点长,总结一下重点: 1.调试项目的两种方法. 2.运行项目的两种窗口选 ...

  2. PerfView专题 (第二篇):如何寻找 C# 中的 Heap堆内存泄漏

    一:背景 上一篇我们聊到了如何去找 热点函数,这一篇我们来看下当你的程序出现了 非托管内存泄漏 时如何去寻找可疑的代码源头,其实思路很简单,就是在 HeapAlloc 或者 VirtualAlloc ...

  3. PerfView专题 (第一篇):如何寻找热点函数

    一:背景 准备开个系列来聊一下 PerfView 这款工具,熟悉我的朋友都知道我喜欢用 WinDbg,这东西虽然很牛,但也不是万能的,也有一些场景他解决不了或者很难解决,这时候借助一些其他的工具来辅助 ...

  4. Pytorch_第九篇_神经网络中常用的激活函数

    神经网络中常用的激活函数 Introduce 理论上神经网络能够拟合任意线性函数,其中主要的一个因素是使用了非线性激活函数(因为如果每一层都是线性变换,那有啥用啊,始终能够拟合的都是线性函数啊).本文 ...

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

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

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

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

  7. 第九篇 Flask 中的蓝图(BluePrint)

    第九篇 Flask 中的蓝图(BluePrint)   蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? ...

  8. Flask最强攻略 - 跟DragonFire学Flask - 第九篇 Flask 中的蓝图(BluePrint)

    蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看 ...

  9. 解剖SQLSERVER 第九篇 OrcaMDF现在能通过系统DMVs显示元数据(译)

    解剖SQLSERVER 第九篇  OrcaMDF现在能通过系统DMVs显示元数据(译) http://improve.dk/orcamdf-now-exposes-metadata-through-s ...

随机推荐

  1. NB-IoT无线通信模块与Lora无线通信协议技术分析与前景展望

    物联网的快速发展对无线通信技术提出了更高的要求,专为低带宽.低功耗.远距离.大量连接的物联网应用而设计的LPWAN(low-power Wide-Area Network,低功耗广域网)也快速兴起.物 ...

  2. 攻防世界pwn题:实时数据检测

    0x00:查看文件 一个32位的文件,canary.NX.PIE保护机制均关闭. 0x01:用IDA进行静态分析 程序很简单,输入一串字符(个数限制:512),然后再输出.最后根据key变量进行条件语 ...

  3. 如何正确理解古典概率中的条件概率 《考研概率论学习之我见》 -by zobol

    "B事件发生的条件下,A事件发生的概率"? "在A集合内有多少B的样本点"? "在B约束条件下,A发生的概率变化为?" "B事件中 ...

  4. 内存泄漏定位工具之 valgrind 使用

    1 前言 前面介绍了 GCC 自带的 mtrace 内存泄漏检查工具,该篇主要介绍开源的内存泄漏工具 valgrind,valgrind 是一套 Linux 下,开放源代码的动态调试工具集合,能够检测 ...

  5. 【题解】Educational Codeforces Round 82

    比较菜只有 A ~ E A.Erasing Zeroes 题目描述: 原题面 题目分析: 使得所有的 \(1\) 连续也就是所有的 \(1\) 中间的 \(0\) 全部去掉,也就是可以理解为第一个 \ ...

  6. 内存分析器 (MAT)

    内存分析器 (MAT) 1. 内存分析器 (MAT) 1.1   MAT介绍 MAT是Memory Analyzer tool的缩写.指分析工具. 1.2   MAT作用 Eclipse Memory ...

  7. Linux操作系统(6):进程管理和服务管理

    进程的基本介绍 1)在 LINUX 中,每个执行的程序(代码)都称为一个进程.每一个进程都分配一个 ID 号. 2)每一个进程,都会对应一个父进程,而这个父进程可以复制多个子进程.例如 www 服务器 ...

  8. 文件的下载,HttpMessageConverter原理

    HttpMessageConverter<T> 1) HttpMessageConverter<T> 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类 ...

  9. vue2升级vue3指南(一)—— 环境准备和构建篇

    1.nodejs和npm 注意二者的版本,版本过低需要升级,本人升级后的版本如下: $ node -v v16.15.1 $ npm -v 8.11.0 2.package.json 和依赖升级 由于 ...

  10. Solution -「2021.11.27」\Infty

    T1. 显然往 \(x < 0, y < 0\) 的点走一定不优. 根据转移式可发现 \(C(x, y)\) 即从 \((0, 0)\) 走到 \((x, y)\) 的方案数 \(\dbi ...