張銀奎老師的<軟體調試>第23章提到可以用windbg !heap -v HeapHandle來檢視堆解除送出的粒度。我在win7 32bit機器上測試系統堆解除送出的情況,得到了不同的結果。
首先我的系統堆位址是0x360000:
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)
系統堆解除送出的粒度是0x2000,是以0x2000*8=0x10000=65536B,即堆上有64KB的空閑記憶體就會釋放記憶體。
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