windows 2000 堆管理的一点心得和体会

  windows 2000堆管理 较为复杂 基本是通过三种方式来管理堆 分别是sidealook  freelist  cache

  freelist是个双向连表 把同样大小的空闲的对快连接到一起

  freelist ------------------->0x0  这里是大于1024的空闲堆

                                          0x01 大小为0x1*8的空闲堆

                                          0x02  大小为0x2*8的空闲堆

 依此类推 freelist总共有128项 128*8也就是1024

 空闲堆双向连表的指针互写 来增加或者减少空闲堆连表

 空闲堆通过 空闲位图 来进行快速的搜索

  结构如下

  union{

              ULONG   FreeListInUseUlong[4];

              UCHAR   FreeListInUseBytes[16];

}

 如果表项使用则为1 否则为0 这128个位正好能够描述表项的128项

  lookaside是一个单项的忙块

  通过结构

 typedef  union  _SLIST_HEADER {

                ULONGULONG Alignment;

               struct{

                           SLIST_HEADER_ENTRY  Next;

                           USHORT  Depth;

                           SUHORT  Sequence;

                           }

}SLIST_HEADER,*PSLIST_HEADER;

typedef   struct  _SLIST_HEADER_ENTRY{

               struct  _SLIST_HEADER_ENTRY  *next;

}SLIST_HEADER_ENTRY,*PSLIST_HEADER_ENTRY;

  连接到一起的

  cache 这个资料实在太少了 不是太清楚 

  默认情况下是禁用的 只有当程序短暂时间使用大的内存快的时候才会被使用

  大于1k的内存块 如果cache存在的话 讲先于freelist使用 cache的索引号是 快大小减去1k除以8

  共有896项 所以大于8k的块均放在cachetable[895]当中

  与freelist同样是利用位图搜索的

  其中的结构不打清楚没有找到相关的资料

  堆有 两个很重要的管理结构

  typedef struct _HEAP_ENTRY {

   USHORT Size;//当前堆的大小,实际大小除8

   USHORT PreviousSize;//上一个堆的大小

   UCHAR SegmentIndex;//指向堆段数组指针的索引

    //  0x01 - HEAP_ENTRY_BUSY
    //  0x02 - HEAP_ENTRY_EXTRA_PRESENT
    //  0x04 - HEAP_ENTRY_FILL_PATTERN
    //  0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
    //  0x10 - HEAP_ENTRY_LAST_ENTRY
    //  0x20 - HEAP_ENTRY_SETTABLE_FLAG1
    //  0x40 - HEAP_ENTRY_SETTABLE_FLAG2
    //  0x80 - HEAP_ENTRY_SETTABLE_FLAG3
    //

  UCHAR Flags;

  UCHAR UnusedBytes;//分配块多出的字节数

  UCHAR SmallTagIndex;

} HEAP_ENTRY, *PHEAP_ENTRY;

 

typedef struct _HEAP_FREE_ENTRY {
     USHORT Size;

    USHORT PreviousSize;

    UCHAR SegmentIndex;

    
    //  0x02 - HEAP_ENTRY_EXTRA_PRESENT
    //  0x04 - HEAP_ENTRY_FILL_PATTERN
    //  0x10 - HEAP_ENTRY_LAST_ENTRY
    //

    UCHAR Flags;

    UCHAR Index;
    UCHAR Mask;


    //
    LIST_ENTRY FreeList;

} HEAP_FREE_ENTRY, *PHEAP_FREE_ENTRY;

此块的意义基本和HEAP_ENTRY 相同

 HEAP_ENTRY 是用于管理以分配的内存块

  HEAP_FREE_ENTRY用于管理空闲块

  其中list_entry是一个双项的链表

  用于连接空闲块

  分配堆的时候 先从looaside开始

  当lookaside存在 且可以操作 堆的大小小于1024 刚好能够满足用户的需求的时候就从lookaside中移除 返回给用户

  如果没能够从lookaside中获得 有关的对

  则从freelist中进行搜索 搜索可用的空闲列表 如果有大于用户的请求的堆  则分给用户 当多于用户请求大小16 字节的时候 尽分给用用户需要的部分 剩余的部分 形成新头 从新插入到列表的适合部分  

  如果 freelist当中没有找到 且存在cache 的时候 从cache当中寻找 适合的大小 如果依然未找到 则从freelist[0]中寻找

  连续分配的堆块 会被连接到一起

  如

  | _____x______|_____________________________| _______y ________|_____________________|

 x y 分别是堆块的控制头

  当执行free操作的时候 分别释放 x y 的时候 三个块会合并到一起 只有一个x控制头 来表述这一内存块

 在释放长度超过508k的时候将不会被连接 首块和末块不回向后和前连接

 在win2000 sp4上大致写了个演示程序 不具备通用性 只是为了更深入的了解堆

 如下

 // heap.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>

#define OFFSET                    1024

#define HEAP_ENTRY_BUSY             0x01
#define HEAP_ENTRY_EXTRA_PRESENT    0x02
#define HEAP_ENTRY_FILL_PATTERN     0x04
#define HEAP_ENTRY_VIRTUAL_ALLOC    0x08
#define HEAP_ENTRY_LAST_ENTRY       0x10
#define HEAP_ENTRY_SETTABLE_FLAG1   0x20
#define HEAP_ENTRY_SETTABLE_FLAG2   0x40
#define HEAP_ENTRY_SETTABLE_FLAG3   0x80
#define HEAP_ENTRY_SETTABLE_FLAGS   0xE0

typedef struct _HEAP_FREE_ENTRY {
    USHORT Size;
    USHORT PreviousSize;
    UCHAR SegmentIndex;
    UCHAR Flags;
    UCHAR Index;
    UCHAR Mask;
    LIST_ENTRY FreeList;
} HEAP_FREE_ENTRY, *PHEAP_FREE_ENTRY;
int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE      hHeap;
 char buff[20];
 char *buf1,*buf2,*buf3;
 PHEAP_FREE_ENTRY pfheap_entry;
    hHeap = GetProcessHeap();

 buf1 = (char*)HeapAlloc(hHeap,0,OFFSET);//申请堆块buf1
 memset(buff,0,20);
 memset(buf1,0,OFFSET);
 buf2 = (char*)HeapAlloc(hHeap,0,OFFSET);//申请堆块buf2
 memset(buf2,0,OFFSET);

 pfheap_entry                 = (PHEAP_FREE_ENTRY)&buff;
 pfheap_entry->PreviousSize   = 0x83;
 pfheap_entry->Size           = 0x5;
 pfheap_entry->SegmentIndex   = 0x0;
 pfheap_entry->Flags          = HEAP_ENTRY_SETTABLE_FLAG2 | HEAP_ENTRY_BUSY;
 pfheap_entry->Index          = 0x18;//其中包括 8字节 管理头 16字节空闲内存 (再分配块的后面)
 pfheap_entry->Mask           = 0x0;

 memcpy(buf2+16+16,buf1+1024+16,8);//复制buf2的管理头 到改变管理结构后面的地方 以便从新组织下一个堆 这里 buf2 +16+16 第一个16是修改后buf2的大小 第二个16 是 pfheap_entry->Index  -8 得到的

//将堆块buf2改写 改变它的大小从1024 降到 16

 memcpy(buf1+1024+16,pfheap_entry,sizeof(_HEAP_FREE_ENTRY ));

 memcpy(buf2+16,buf1+1024,8);//修改buf2后面的空闲块

 pfheap_entry                 = (PHEAP_FREE_ENTRY)(buf2+32);
 pfheap_entry->PreviousSize   =  0x2;
 pfheap_entry->Size = pfheap_entry->Size-5;

 buf3 = buf2+40;

//上面是修改 以前buf2的管理头 使之成为buf3

 HeapFree(hHeap, 0, buf1);
 HeapFree(hHeap, 0, buf2);
 HeapFree(hHeap, 0, buf3);

//释放三个堆 通过端点观察 可以看到内存当中对于 空闲堆管理结构 和 分配堆管理结构的修改
  return 0;
}

堆的一些重要结构 摘抄自win2000 code

typedef struct _HEAP {
    HEAP_ENTRY Entry;

    ULONG Signature;
    ULONG Flags;
    ULONG ForceFlags;
    ULONG VirtualMemoryThreshold;

    SIZE_T SegmentReserve;
    SIZE_T SegmentCommit;
    SIZE_T DeCommitFreeBlockThreshold;
    SIZE_T DeCommitTotalFreeThreshold;

    SIZE_T TotalFreeSize;
    SIZE_T MaximumAllocationSize;
    USHORT ProcessHeapsListIndex;
    USHORT HeaderValidateLength;
    PVOID HeaderValidateCopy;

    USHORT NextAvailableTagIndex;
    USHORT MaximumTagIndex;
    PHEAP_TAG_ENTRY TagEntries;
    PHEAP_UCR_SEGMENT UCRSegments;
    PHEAP_UNCOMMMTTED_RANGE UnusedUnCommittedRanges;

    //
    //  The following two fields control the alignment for each new heap entry
    //  allocation.  The round is added to each size and the mask is used to
    //  align it.  The round value includes the heap entry and any tail checking
    //  space
    //

    ULONG AlignRound;
    ULONG AlignMask;

    LIST_ENTRY VirtualAllocdBlocks;

    PHEAP_SEGMENT Segments[ HEAP_MAXIMUM_SEGMENTS ];

    union {
        ULONG FreeListsInUseUlong[ HEAP_MAXIMUM_FREELISTS / 32 ];
        UCHAR FreeListsInUseBytes[ HEAP_MAXIMUM_FREELISTS / 8 ];
    } u;//位图

    USHORT FreeListsInUseTerminate;
    USHORT AllocatorBackTraceIndex;
    ULONG Reserved1[2];
    PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries;

    LIST_ENTRY FreeLists[ HEAP_MAXIMUM_FREELISTS ];//空闲链表

    PHEAP_LOCK LockVariable;
    PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;

    //
    //  The following field is used to manage the heap lookaside list.  The
    //  pointer is used to locate the lookaside list array.  If it is null
    //  then the lookaside list is not active.
    //
    //  The lock count is used to denote if the heap is locked.  A zero value
    //  means the heap is not locked.  Each lock operation increments the
    //  heap count and each unlock decrements the counter
    //

    PVOID Lookaside;//lookaside
    ULONG LookasideLockCount;

} HEAP, *PHEAP;

 typedef struct _HEAP_SEGMENT {
    HEAP_ENTRY Entry;

    ULONG Signature;
    ULONG Flags;
    struct _HEAP *Heap;
    SIZE_T LargestUnCommittedRange;

    PVOID BaseAddress;
    ULONG NumberOfPages;
    PHEAP_ENTRY FirstEntry;
    PHEAP_ENTRY LastValidEntry;

    ULONG NumberOfUnCommittedPages;
    ULONG NumberOfUnCommittedRanges;
    PHEAP_UNCOMMMTTED_RANGE UnCommittedRanges;
    USHORT AllocatorBackTraceIndex;
    USHORT Reserved;
    PHEAP_ENTRY LastEntryInSegment;
} HEAP_SEGMENT, *PHEAP_SEGMENT;


typedef struct _HEAP_LOOKASIDE {
    SLIST_HEADER ListHead;

    USHORT Depth;
    USHORT MaximumDepth;

    ULONG TotalAllocates;
    ULONG AllocateMisses;
    ULONG TotalFrees;
    ULONG FreeMisses;

    ULONG LastTotalAllocates;
    ULONG LastAllocateMisses;

    ULONG Future[2];

} HEAP_LOOKASIDE, *PHEAP_LOOKASIDE;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值