軟體除錯23章 堆管理器向記憶體管理器釋放的疑惑
阿新 • • 發佈:2019-01-29
張銀奎老師的<軟體除錯>第23章提到可以用windbg !heap -v HeapHandle來檢視堆解除提交的粒度。我在win7 32bit機器上測試系統堆解除提交的情況,得到了不同的結果。
首先我的系統堆地址是0x360000:
系統堆解除提交的粒度是0x2000,因此0x2000*8=0x10000=65536B,即堆上有64KB的空閒記憶體就會釋放記憶體。0:001> !heap -a Index Address Name Debugging options enabled 1: 00360000 Segment at 00360000 to 00460000 (00028000 bytes committed) 2: 00010000 - heap headers inaccessible, skipping 3: 00020000 - heap headers inaccessible, skipping 4: 00320000 Segment at 00320000 to 00330000 (00005000 bytes committed)
0:001> !heap -v 0x00360000 Index Address Name Debugging options enabled 1: 00360000 Segment at 00360000 to 00460000 (00028000 bytes committed) Flags: 00000002 ForceFlags: 00000000 Granularity: 8 bytes Segment Reserve: 00100000 Segment Commit: 00002000 DeCommit Block Thres: 00000800 DeCommit Total Thres: 00002000 Total Free Size: 000003ad
3張圖依次是分配堆塊前,分配後,釋放後,程式在工作管理員中顯示的vm大小。
可以看到分配和釋放前後,vm的大小沒有改變。
這就很奇怪了,我不斷嘗試增加申請和釋放的堆記憶體數量,直到分配釋放的堆記憶體數量接近512KB時候,在工作管理員中有明顯的decommit動作。
最後,我檢視peb中關於堆釋放的粒度總算找到了解釋這個疑惑的點:
0:001> dt _peb @$peb
HiHeapVC8!_PEB
+0x080 HeapDeCommitTotalFreeThreshold : 0x10000
+0x084 HeapDeCommitFreeBlockThreshold : 0x1000
當堆上的總空閒空間達到:0x10000(顆粒度)*8(單位)=0x80000B(512KB)時,堆管理器才會立即向記憶體管理器執行decommit操作,真正釋放記憶體。另外decommit釋放記憶體不一定發生在釋放512KB,在508KB的時候就會釋放。我的猜測可能是因為程序堆上本來就有空閒記憶體,加上本次釋放的記憶體,正好夠上512KB,因此觸發了釋放操作