国产精品免费嫩草研究院|无遮羞动漫在线观看AV|国产麻豆精品传媒AV国产在线|村在线观看|寂寞情人1正版|韩国床震韩国床震古|精品系列专区久久

C# 內存泄漏之 Internal 關鍵詞代表什么?

一:背景1. 背景前段時間有位朋友咨詢說他的程序出現了非托管內存泄漏,說里面有很多的 HEAP_BLOCK 都被標記成了 Internal 狀態,而且 size 都很大,讓我幫忙看下怎么回事? 比如下面這樣 。
【C# 內存泄漏之 Internal 關鍵詞代表什么?】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 關鍵詞代表什么?

文章插圖
從圖中可以清晰的看到,當 Heap_Entry 標記了Internel ,其實是給 前段堆 LFH 做內部存儲用的,當然這里的大塊內存是按有序的 segmentblock 切分,相當于堆中堆。
接下來我們驗證下這個說法到底對不對? 寫一個測試程序,讓其在 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-----------------------------------------------------------------------------

經驗總結擴展閱讀