软件调试23章 堆管理器向内存管理器释放的疑惑

63 篇文章 4 订阅

    张银奎老师的<软件调试>第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
当堆上的总空闲空间达到:0x10000(颗粒度)*8(单位)=0x80000B(512KB)时,堆管理器才会立即向内存管理器执行decommit操作,真正释放内存。另外decommit释放内存不一定发生在释放512KB,在508KB的时候就会释放。我的猜测可能是因为进程堆上本来就有空闲内存,加上本次释放的内存,正好够上512KB,因此触发了释放操作

前言 上一次发布过的程序:【首发】检测文件的占用,具有学习和商业价值(By超级用户),可以使用,仿电脑管家 正文 对于怎么枚举文件句柄 ,上一帖子对此有介绍,核心代码大概如下:如果 (ZwQueryObject (handle, #ObjectTypeInformation, unicode, 0, size) ≠ #STATUS_INVALID_HANDLE )' 只要不是无效的,为什么,详细看下面的注释 ' 参数 ' Handle ' 对象的一个句柄来获取信息。 ' ObjectInformationClass ' 指定一个OBJECT_INFORMATION_CLASS返回值的类型决定了信息在ObjectInformation缓冲区。 ' ObjectInformation ' 一个指向caller-allocated缓冲接收请求的信息。 ' ObjectInformationLength ' 指定的大小,以字节为单位,ObjectInformation缓冲区。 ' ReturnLength ' 一个指向变量的指针,接收的大小,以字节为单位,请求的关键信息。如果NtQueryObject STATUS_SUCCESS返回,返回的变量包含的数据量。如果NtQueryObject返回STATUS_BUFFER_OVERFLOW或STATUS_BUFFER_TOO_SMALL,您可以使用变量的值来确定所需的缓冲区大小。 ' 返回值 ' NtQueryObject返回STATUS_SUCCESS或适当的错误状态。可能的错误状态码包括以下: ' 返回代码 描述 ' STATUS_ACCESS_DENIED ' 有足够的权限来执行该cha询。 ' STATUS_INVALID_HANDLE ' 提供对象句柄无效。 ' STATUS_INFO_LENGTH_MISMATCH ' 信息长度不足以容纳数据。 unicode = 取空白字节集 (size) ZwQueryObject (handle, #ObjectTypeInformation, unicode, size, 0)' 读取信息的unicode文本 RtlUnicodeStringToAnsiString (ansi, unicode, 真)' 编码转换 ' RtlUnicodeStringToAnsiString例程将给定Unicode字符串转换成一个ANSI字符串。 str = 指针到文本 (ansi.Buffer) ' RtlFreeAnsiString常规版本存储由RtlUnicodeStringToAnsiString分配。 ' 参数 ' AnsiString ' 指针ANSI字符串缓冲区由RtlUnicodeStringToAnsiString以前分配的。 RtlFreeAnsiString (ansi) str = “无法获取”' 无效的怎么获取…… 返回 (str) 这一次呢更新了一个RemoteCloseHandle ,大概的原理是什么呢? 同时也采用了一些比较骚的方法,这种方法的限制较多,但是对于32位进程就很有效果。 NtClose在MSDN的大概介绍 1. NtClose is a generic routine that operates on any type of object. 2. Closing an open object handle causes that handle to become invalid. The system also decrements the handle count for the object and checks whether the object can be deleted. The system does not actually delete the object until all of the object's handles are closed and no referenced pointers remain. 3. A driver must close every handle that it opens as soon as the handle is no longer required. Kernel handles, which are those that are opened by a system thread or by specifying the OBJ_KERNEL_HANDLE flag, can be closed only when the previous processor mo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值