PerfView专题 (第九篇):洞察 C# 中的 LOH 内存碎片化
一:背景
在 内存泄漏
的系列问题中,有一类问题是 内存碎片化
导致的,而且这种更容易发生在 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 内存碎片化的更多相关文章
- Egret入门学习日记 --- 第九篇(书中 2.7~2.8节 内容)
第九篇(书中 2.7~2.8节 内容) 昨天记录到了 2.6节 ,那么今天就从 2.7节 开始. 这个 2.7节 有7个小段,有点长,总结一下重点: 1.调试项目的两种方法. 2.运行项目的两种窗口选 ...
- PerfView专题 (第二篇):如何寻找 C# 中的 Heap堆内存泄漏
一:背景 上一篇我们聊到了如何去找 热点函数,这一篇我们来看下当你的程序出现了 非托管内存泄漏 时如何去寻找可疑的代码源头,其实思路很简单,就是在 HeapAlloc 或者 VirtualAlloc ...
- PerfView专题 (第一篇):如何寻找热点函数
一:背景 准备开个系列来聊一下 PerfView 这款工具,熟悉我的朋友都知道我喜欢用 WinDbg,这东西虽然很牛,但也不是万能的,也有一些场景他解决不了或者很难解决,这时候借助一些其他的工具来辅助 ...
- Pytorch_第九篇_神经网络中常用的激活函数
神经网络中常用的激活函数 Introduce 理论上神经网络能够拟合任意线性函数,其中主要的一个因素是使用了非线性激活函数(因为如果每一层都是线性变换,那有啥用啊,始终能够拟合的都是线性函数啊).本文 ...
- PerfView专题 (第十一篇):使用 Diff 功能洞察 C# 内存泄漏增量
一:背景 去年 GC架构师 Maoni 在 (2021 .NET 开发者大会) [https://ke.segmentfault.com/course/1650000041122988/section ...
- PerfView专题 (第十二篇):对 C# 下的 SDK 类库进行监控(大结局)
一:背景 本篇是我们系列文章的最后一篇,前面的文章中大多是在 CLR Runtime 以及 OS 层面进行监控来发现各种可疑的程序问题,除了这两个层面,其实我们还可以对 SDK 中一些类进行洞察,比如 ...
- 第九篇 Flask 中的蓝图(BluePrint)
第九篇 Flask 中的蓝图(BluePrint) 蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? ...
- Flask最强攻略 - 跟DragonFire学Flask - 第九篇 Flask 中的蓝图(BluePrint)
蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看 ...
- 解剖SQLSERVER 第九篇 OrcaMDF现在能通过系统DMVs显示元数据(译)
解剖SQLSERVER 第九篇 OrcaMDF现在能通过系统DMVs显示元数据(译) http://improve.dk/orcamdf-now-exposes-metadata-through-s ...
随机推荐
- Keil软件下用Jlink无法识别芯片
Keil软件下用Jlink无法识别芯片 硬件:正点原子探索者 软件:keil J-Link固件版本:V9.40 J-Link V6.94b驱动:下载地址 跟着视频教程走,发现的第一个问题就是这个,记录 ...
- 物联网lora无线数传模块应用案例:LoRawan网关通信技术
什么是LoRa LoRa(Long Range) 无线通信技术是 Semtech 在2012年开发出来的一款适合物联网使用的射频IC.其设计理念为低功耗.长距离.低成本.网路简单.易于扩展的无线数传技 ...
- 2.如何正确理解古典概率中的条件概率《zobol的考研概率论教程》
写本文主要是帮助粉丝理解考研中的古典概率-条件概率的具体定义. "B事件发生的条件下,A事件发生的概率"? "在A集合内有多少B的样本点"? "在B约 ...
- 使用HBuilder X编辑器安装终端窗口插件未响应的解决方案
一.打开HBuilder X根目录 依次找到main.js HBuilderX \ plugins \ builtincef3terminal \ script \ main.js 二.编辑main. ...
- tableSizeFor
HashMap tableSizeFor() /** Returns a power of two size for the given target capacity. 1.(不考虑大于最大容量的情 ...
- Python Socket Sever
1. Server code 1 # !/usr/bin/env python 2 # coding:utf-8 3 import multiprocessing 4 import socket 5 ...
- Windows 启动过程
引言 启动过程是我们了解操作系统的第一个环节.了解 Windows 的启动过程,可以帮助我们解决一些启动的问题,也能帮助我们了解 Windows 的整体结构. 以下内容将分为[加载内核].[内核初始化 ...
- 详细图解 Netty Reactor 启动全流程 | 万字长文 | 多图预警
本系列Netty源码解析文章基于 4.1.56.Final版本 大家第一眼看到这幅流程图,是不是脑瓜子嗡嗡的呢? 大家先不要惊慌,问题不大,本文笔者的目的就是要让大家清晰的理解这幅流程图,从而深刻的理 ...
- 霍普菲尔得神经网络(Hopfield Neural Network)
设计一个反馈网络存储下列目标平衡点: T = [ 1 -1; -1 1 ]; 并用6组任意随机初始列矢量,包括一组在目标平衡点连线的垂直平分线上的一点作为输入矢量对所设计的网络的平衡点进行测试,观 ...
- 智能指针思想实践(std::unique_ptr, std::shared_ptr)
1 smart pointer 思想 个人认为smart pointer实际上就是一个对原始指针类型的一个封装类,并对外提供了-> 和 * 两种操作,使得其能够表现出原始指针的操作行为. ...