一:背景

内存泄漏 的系列问题中,有一类问题是 内存碎片化 导致的,而且这种更容易发生在 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. 【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest)

    问题描述 在上一篇博文 "[Azure 应用服务]NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤"中, ...

  2. bootstrap 4.0 dropdown 找不到popper.js 的解决方案

    最近项目中升级bootstrap 由3.3.7版 升了4.0版本 发现 dropdown 找不到popper.js 解决办法:npm install -save popper 下载完之后,查看node ...

  3. 【Redis】集群数据迁移

    Redis通过对KEY计算hash,将KEY映射到slot,集群中每个节点负责一部分slot的方式管理数据,slot最大个数为16384. 在集群节点对应的结构体变量clusterNode中可以看到s ...

  4. 解决Invalid bound statement (not found)的异常

    今天在搭建框架的时候,报了一个Invalid bound statement (not found)的异常 经过分析,得出原因: 我的mybatis相关的dao和mapper.xml是通过逆向工程生成 ...

  5. 根据数据中的key获取value值

    一.测试数据准备 List<Map<String, String>> result = new ArrayList();Map<String, String> ma ...

  6. React中setState方法说明

    setState跟新数据是同步还是异步? setState跟新数据是异步的. 如何用代码表现出来是异步的. 点击按钮更新数据,然后去打印这个值看一下 setState跟新数据是异步的 class Fa ...

  7. 一个紧张刺激的聊天器,要不要进来看看(Python UDP网络模型)

    先来哔哔两句:(https://jq.qq.com/?_wv=1027&k=QgGWqAVF) 互联网的本质是什么?其实就是信息的交换.那么如何将自己的信息发送到其他人的电脑上呢?那就需要借助 ...

  8. 使用Visio 2007画用例图没有include(包含)关系且包含关系使用的线不是虚线的解决办法

    使用Visio 2007画用例图没有include(包含)关系且包含关系使用的线不是虚线的解决办法 1 在工具栏选择UML------>选择构造型 如下操作 2 拖动 "扩展" ...

  9. Centos8安装NextCloud记录

    今天在网上学习了这个Nextcloud 网盘的搭建,被折磨的快崩溃了.始终是找不到答案,我在网上查了2天的资料 还是没有找到答案,今天这里总结一下安装的下面的总结: 原文出处在官网:CentOS 8 ...

  10. XXXX系统测试计划

    XXXX系统测试计划 目录 XXXX系统测试计划 目标 概述 项目背景 适用范围 组织形式 组织架构图 角色及职责 测试工作分工 团队协作 测试对象 应测试特性 不被测试特性 测试任务安排 系统测试任 ...