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;