Windows进程堆

前言

进程堆是进程非常重要的内存区域,它里面含有了进程中分配的变量信息等,一个进程被创建时会自动创建一个默认堆,进程默认堆非常重要,系统要求进程中的线程依次访问默认堆,意味如果一个线程要对默认堆分配内存,那么其他线程一定要处于等待状态。一个进程在运行时 会创建多个堆,这些堆可以创建,也可以销毁。调用GetProcessHeap可以获取默认堆

HANDLE GetProcessHeap();

堆的创建

进程运行时产生的数据不能都放在默认堆中,因此需要创建额外的堆来存放信息,创建堆的函数如下:

HANDLE HeapCreate(
DWORD flOptions , 
DWORD dwInitialSize ,
 DWORD dwMaxmumSize);

第一个参数flOptions 表明对堆的操作,取证范围是:0、HEAP_NO_SERIALIAZE、HEAP_CREATE_ENABLE_EXECUTE、HEAP_GENERATE_EXCEPTIONS

取值 含义
HEAP_NO_SERIALIAZE 表明线程对堆的操作是非互斥的,不需要依次访问创建的堆、但是这个标志不能应用在低碎片化堆中
HEAP_CREATE_ENABLE_EXECUTE 从该堆分配的所有内存块均允许执行代码
HEAP_GENERATE_EXCEPTIONS 系统引发异常以指示对HeapAlloc和HeapReAlloc的调用失败(例如,内存不足的情况),而不是返回NULL。

第二个参数是设置分配堆的内存初始化大小
第三个参数是设置堆的最大大小,如果值为0的话表明堆的内存大小没有限制,可以不断增长。

块的创建

创建了堆之后,就需要创建内存块来存放信息,系统提供了创建内存块的函数,下面是创建块的函数

DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
  HANDLE hHeap,
  DWORD  dwFlags,
  SIZE_T dwBytes
);

第一个参数hHeap表明,在哪个堆中分配内存块;
第二个参数表明堆分配选项,指定这些值中的任何一个都将覆盖使用HeapCreate创建堆时指定的相应值。 此参数可以是以下一个或多个值。

取值 含义
HEAP_GENERATE_EXCEPTIONS 系统将引发异常以指示功能故障(例如内存不足情况),而不是返回NULL。
HEAP_NO_SERIALIZE 线程不依次访问内存块
HEAP_ZERO_MEMORY 分配的内存将初始化为零, 否则,内存不会初始化为零。

第三个参数表明分配的字节数

调整块的大小

块创建之后,大小可以重调,为了不浪费内存可以调小,为了能够使用到足够的内存,可以调大,重调函数如下:

DECLSPEC_ALLOCATOR LPVOID HeapReAlloc(
  HANDLE                 hHeap,
  DWORD                  dwFlags,
  _Frees_ptr_opt_ LPVOID lpMem,
  SIZE_T                 dwBytes
);

第一个参数hHeap表明,在哪个堆中的内存块需要重调;
第二次参数是堆重新分配选项。 使用HeapCreate函数创建堆时,指定值将覆盖flOptions参数中指定的相应值。取值情况如下:

取值 含义
HEAP_GENERATE_EXCEPTIONS 操作系统引发异常以指示功能故障(例如内存不足情况),而不是返回NULL。
HEAP_NO_SERIALIZE 同上
HEAP_REALLOC_IN_PLACE_ONLY 重新分配内存块时不能移动。 如果未指定该值,则该功能可能会将块移动到新位置。 如果指定了该值并且无法移动就无法调整该块的大小,则该功能将失败,从而使原始存储块保持不变。
HEAP_ZERO_MEMORY 如果重新分配请求用于更大的大小,则超出原始大小的其他内存区域将初始化为零。 直到其原始大小的存储块的内容均不受影响。

第三个参数是指向该函数重新分配的内存块的指针。 该指针是通过较早调用HeapAlloc或HeapReAlloc函数返回的。
第四个参数是重新分配块的大小

销毁堆

堆既然能被创建就能被销毁,当程序不再需要自己的堆时,程序可以自动销毁它,但程序不主动销毁它的话,系统只能等进程被终止了,系统才自动销毁它,销毁堆的函数如下:

BOOL HeapDestroy(
  HANDLE hHeap
);

成功销毁则返回true,否则返回false

堆的使用

我们平时编程的时候,很少直接去调用堆相关的api去创建和操作堆,但我们却经常用到堆,比如在c++中的new 操作,new操作就是在堆中分配内存,为了形象显示new创建的堆的过程,我借鉴了如下代码:

class CSomeClass{
public:
    static HANDLE s_handle;
    static UINT s_allocInheap;

public:
    void* operator new(size_t hsize);
    void operator delete(void* p);

};
void* CSomeClass::operator new(size_t hsize)
{
    if(s_handle==NULL)
    {
        s_handle=HeapCreate(HEAP_NO_SERIALIZE,0,0);
        if(s_handle==NULL)
            return NULL;
    }
    void* p=HeapAlloc(s_handle,0,hsize);
    if(p!=NULL)
        s_allocInheap++;
    else
        return NULL;
    return (p);
}

上面的代码,覆盖了系统的new操作,当调用一次new操作时,程序就会分配一个内存块并让块数加1.

遍历所有堆

Windows api里有GetProcessHeaps这个函数,该函数可以获取进程创建的所有堆,遍历所有堆之前需要自定义一个句柄数组。GetProcessHeaps函数如下:

HANDLE GetProcessHeaps(
DWORD dWNumHeaps,
PHANDLE phHeaps
);
发布了30 篇原创文章 · 获赞 48 · 访问量 1094

猜你喜欢

转载自blog.csdn.net/qq_33526144/article/details/103960707
今日推荐