一:背景1. 背景前段时间有位朋友咨询说他的程序出现了非托管内存泄漏,说里面有很多的 HEAP_BLOCK
都被标记成了 Internal
状态,而且 size 都很大 , 让我帮忙看下怎么回事? 比如下面这样 。
1cbea000: 42000 . 42000 [101] - busy (41fe8) Internal1cc2c000: 42000 . 42000 [101] - busy (41fe8) Internal1cc6e000: 42000 . 42000 [101] - busy (41fe8) Internal1ccb0000: 42000 . 42000 [101] - busy (41fe8) Internal1ccf2000: 42000 . 42000 [101] - busy (41fe8) Internal1cd34000: 42000 . 42000 [101] - busy (41fe8) Internal1cd76000: 42000 . 42000 [101] - busy (41fe8) Internal1cdb8000: 42000 . 42000 [101] - busy (41fe8) Internal1cdfa000: 42000 . 42000 [101] - busy (41fe8) Internal1ce3c000: 42000 . 42000 [101] - busy (41fe8) Internal
其实这个涉及到了 NTHeap 的一些基础知识 。
二:原理浅析1. NTHeap 分配架构图千言万语不及一张图 。
![C# 内存泄漏之 Internal 关键词代表什么?](http://img.zhejianglong.com/231017/23253GN7-0.png)
文章插图
从图中可以清晰的看到,当 Heap_Entry 标记了
Internel
,其实是给 前段堆 LFH
做内部存储用的,当然这里的大块内存是按有序的 segment
和 block
切分,相当于堆中堆
。【C# 内存泄漏之 Internal 关键词代表什么?】接下来我们验证下这个说法到底对不对? 写一个测试程序,让其在 NTHeap 上生成大量的
Internel
。2. 案例演示首先来一段 C++ 代码,根据 len 参数来分配
char[]
数组大小 。#include "iostream"#include <Windows.h>using namespace std;extern "C"{ _declspec(dllexport) int__stdcall InitData(int len);}int __stdcall InitData(int len) { char* c = new char[len]; return 1;}
熟悉 C++ 的朋友一眼就能看出会存在内存泄露的情况,因为 c 没有进行 delete[]
。接下来将
InitData
引入到 C# 上,代码如下:internal class Program{[DllImport("Example_16_1_7", CallingConvention = CallingConvention.StdCall)]private static extern int InitData(int len);static void Main(string[] args){var task = Task.Factory.StartNew(() =>{for (int i = 0; i < 10000; i++){InitData(10000);Console.WriteLine($"i={i} 次操作!");}});Console.ReadLine();}}
从代码中可以看到,我做了 1w 次的分配 , 而且 len=1w , 即 1wbyte , 高频且固定,这完全符合进入 LFH 堆的特性 。为了能够记录
block
是谁分配的,在注册表中配置一个 GlobalFlag
项 。SET ApplicationName=Example_16_1_6.exeREG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%ApplicationName% " /f ECHO 已删除注册项REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%ApplicationName%" /v GlobalFlag/t REG_SZ/d 0x00001000 /fREG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%ApplicationName%" /v StackTraceDatabaseSizeInMb/t REG_DWORD/d 0x00000400 /fECHO 已启动用户栈跟踪PAUSE
把程序跑起来,然后抓一个 dump 文件 。三:WinDbg 分析 Internel1. 内存都去了哪里
0:000> !address -summary--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotalFree70e1292000 (3.518 GB)87.95%<unknown>138c42f000 ( 196.184 MB)39.76%4.79%Other11805d000 ( 128.363 MB)26.02%3.13%Heap8326f55000 ( 111.332 MB)22.57%2.72%Image2803061000 (48.379 MB)9.81%1.18%Stack27900000 (9.000 MB)1.82%0.22%TEB919000 ( 100.000 kB)0.02%0.00%PEB13000 (12.000 kB)0.00%0.00%--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotalMEM_FREE70e1292000 (3.518 GB)87.95%MEM_RESERVE9414830000 ( 328.188 MB)66.52%8.01%MEM_COMMIT1204a52e000 ( 165.180 MB)33.48%4.03%0:000> !heap -s************************************************************************************************************************NT HEAP STATS BELOW************************************************************************************************************************NtGlobalFlag enables following debugging aids for new heaps:stack back tracesLFH Key: 0x38843509Termination on corruption : ENABLEDHeapFlagsReservCommitVirtFreeListUCRVirtLockFast(k)(k)(k)(k) lengthblocks cont. heap-----------------------------------------------------------------------------10600000 08000002113704 107896 1134921679721106LFH10560000 080010026016603210010a70000 080010026016602210012450000 080010026046001100123b0000 08041002604602110015ef0000 080410026046001100-----------------------------------------------------------------------------
从卦中可知 , 当前内存都是 Heap 给吃掉了,往细处说就是 10600000
这个进程堆,接下来使用 !heap -h 10600000
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 分布式存储系统之Ceph集群部署
- Springboot 之 HandlerMethodReturnValueHandler 运用
- 哲仁王后女主后来回来了吗_哲仁王后女主之后有没有回来
- 分布式存储系统之Ceph基础
- 原神内存怎么清理
- 二 Java之POI导出Excel:多个sheet
- 光与夜之恋双十一礼包怎么购买
- 光与夜之恋钜惠嘉年华怎么买划算
- 永恒岛之彩虹世界日常必做任务有哪些
- 永恒岛之彩虹世界哪些宠物强度高