非诚勿扰电影1剧情介绍:堆管理

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 02:50:44

用户使用内存分配函数分配的内存都位于堆中,所以使用堆管理函数对内存进行分配,释放等是最直接的方式.
windows系统中,每个进程都有自己的堆,每个进程堆数量也不同,windows系统中所谓的堆(Heap)并不是内存块,
而是一种内存管理对象,是一种内存组织的形式.进程可以从属于自己的堆上分配内存和释放内存.

堆是一种内存管理对象,一个进程有若干该堆,在分配内存前需要指定从哪个堆上进行分配.堆的句柄唯一标识
了一个堆.获得堆句柄两种方式:
1.获取在进程中已经创建好的堆
2.进程自己再创建堆.有了堆的句柄就可在上面分配内存了.
在堆中分配内存,用户不用考虑分页,对齐,内存块可以任意大小.

1.HeapCreate
为进程创建新堆,请求分配虚拟内存分页
HANDLE HeapCreate(
DWORD flOptions,
SIZE_T dwInitialSize,
SIZE_T dwMaximumSize
);
flOptions:输入参数,创建堆选项
HEAP_CREATE_ENABLE_EXECUTE 分配的内存允许用于代码执行
HEAP_GENERATE_EXCEPTIONS    如果分析内存失败会产生异常,而不是返回NULL
HEAP_NO_SERIALIZE           不进行连续存储
dwInitialSize 堆的初始化大小(字节),0,系统自动分配一个内存页大小
dwMaximumSize 堆大小最大值,0表示向上增长
失败返回NULL

2.GetProcessHeap
获取当前进程中的一个堆,返回堆句柄
HANDLE GetProcessHeap(void);
失败返回NULL

3.GetProcessHeaps
获得进程中的所有堆,包括堆的数量和堆的句柄
DWORD GetProcessHeaps(
DWORD NumberOfHeaps,
PHANDLE ProcessHeaps
);
NumberOfHeaps:输入参数,缓冲区ProcessHeap所能存储的句柄个数.
ProcessHeaps:输出参数,指向用于保存进程中所有堆的句柄的内存块,函数返回值句柄值会在其中保存.
返回值:
DWORD类型的数据,进程中堆的个数.返回0,则失败
返回值大于NumberOfHeaps,说明进程中实际的堆数量大于NumberOfHeaps.用于存储句柄值的内存区域太小,
ProcessHeaps指向的内存块没有句柄值。反之小于则ProcessHeaps保存了所有堆的句柄值.

4.从指定堆上分配内存块
LPVOID HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes
);
hHeap:输入参数,表明从此参数指定的堆上进行内存分配.
dwFlags:输入参数,内存分配标志
HEAP_GENERATE_EXCEPTIONS 如果分配错误则抛出异常,而不是返回NULL
         (STATUS_NO_MEMORY内存不足,STATUS_ACCESS_VIOLATIONC存取不合法)
HEAP_NO_SERIALIZE   不使用连续存储
HEAP_ZERO_MEMORY      将分配的内存块中的内容全部清零.
dwBytes:输入参数,需要分配内存区域大小,以字节为单位.
返回新分配的内存指针,失败NULL

5.LPVOID HeapReAlloc(
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem,
SIZE_T dwBytes
);
hHeap:输入参数,表明从此参数指定的堆上进行内存分配.
dwFlags:输入参数,内存分配标志.
HEAP_GENERATE_EXCEPTIONS 如果分配错误则抛出异常,而不是返回NULL
         (STATUS_NO_MEMORY内存不足,STATUS_ACCESS_VIOLATIONC存取不合法)
HEAP_NO_SERIALIZE   不使用连续存储
HEAP_ZERO_MEMORY      与HeapAlloc中作用不同,设置此标志,新增加的内存将被清零,原内存块中数据不会变化.
HEAP_REALLOC_IN_PLACE_ONLY,
HEAP_REALLOC_IN_PLACE_ONLY表示重新分配内存的位置不要发生变化.
lpMem:输入参数,原内存块的地址.
dwBytes:输入参数,内存块大小调整后的值,可以比原来大,也可以小.
返回值:返回成功,返回LPVOID类型数据,是大小调整后内存块的指针.

6.GetSystemInfo
获取系统信息,包括OEM信息,内存块大小,内存分配粒度,处理器信息,内存空间最大值和最小值等.
void GetSystemInfo(
LPSYSTEM_INFO lpSystemInfo
);
lpSystemInfo:输出函数,指向SYSTEM_INFO结构指针,保存获取信息.

7.HeapSize用于获取指定堆大小,以字节为单位返回堆大小信息
SIZE_T HeapSize(
HANDLE hHeap,
DWORD dwFlags,
LPCVOID lpMem
);
hHeap:输入参数,需要获得大小的内存块所在的堆的句柄.
dwFlags:输入参数,内存块标志,可以是HEAP_NO_SERIALIZE
lpMem:所需要获取大小的内存块指针.
返回SIZE_T内存块大小,失败为-1.

8.HeapFree
释放HeapAlloc和HeapReAlloc所分配的内存,函数原型如下:
BOOL HeapFree(
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem
);
hHeap:输入参数,内存块所在的堆,需要使用HeapAlloc和HeapReAlloc分配内存同样的堆.
dwFlags:输入参数,内存块标志,可以设置为HEAP_NO_SERIALIZE
lpMem:输入参数,所需释放的内存块指针.

9.HeapDestroy
销毁由HeapCreate创建的堆,函数原型如下:
BOOL HeapDestroy(
HANDLE hHeap
);
hHeap:输入参数,所需销毁堆的句柄
返回BOOL值,表示是否成功.

code:

/* 头文件 */
#include
#include

/*************************************
* DWORD PrintHeapSize(HANDLE hHeap,LPVOID lpMem)
* 功能 获取堆的大小并打印出来
*
* 参数 HANDLE hHeap,堆句柄
*   LPVOID lpMem,内存地址指针
*
* 返回值 0代表执行完成,1代码发生错误。
**************************************/
DWORD PrintHeapSize(HANDLE hHeap,LPVOID lpMem)
{
SIZE_T dwHeapSize;
dwHeapSize = HeapSize(hHeap,HEAP_NO_SERIALIZE,lpMem);
if(dwHeapSize == -1)
{
   printf("Get HeapSize error :%d",GetLastError());
   return 1;
}
printf("内存块大小为:0x%x\n",dwHeapSize);
return 0;
}

/*************************************
* int main(int argc, PCHAR argv[])
* 功能 演示堆的使用
*
* 参数 argv[1]如果为“-s”那么使用进程堆
*   argv[1]如果为“-a”那么创建一个可变大小的堆
*   argv[1]如果为其他,那么创建有最大大小的堆。
*
*
**************************************/
int main(int argc, PCHAR argv[])
{
SYSTEM_INFO si; //系统信息
HANDLE hHeap; //堆句柄
LPVOID lpMem; //内存块指针
LPVOID lpReAlloc; //内存块大小调整后的指针
DWORD dwHeapSize; //堆内存埠大小
HANDLE hHeaps[24]; //用于保存进程中所有的堆句柄
DWORD dwHeapNum; //进程中堆的数量\
//获取系统信息
GetSystemInfo(&si);
//将系统内存分页大小,与内存分配粒度打印出来。
printf("系统内存页大小: 0x%x\n系统内存分配粒度:0x%x\n",
   si.dwPageSize,si.dwAllocationGranularity);
//分析输入参数,如果是“-a”创建一个最大为10个分页大小的堆
if(argc == 2 && 0==lstrcmp(argv[1],"-a"))
{
   hHeap = HeapCreate(HEAP_NO_SERIALIZE,
    si.dwPageSize,si.dwPageSize*10);
   printf("创建堆,初始化大小为1页,最大为10页\n");
}
//如果输入参数为“-s”使用进程初始化时已经存在的堆
else if(argc == 2 && 0==lstrcmp(argv[1],"-s"))
{
   hHeap = GetProcessHeap();
   printf("获取系统已经存在的堆\n");
}
//如果输入其他,创建一个可增长的堆
else
{
   hHeap = HeapCreate(HEAP_NO_SERIALIZE,0,0);
   printf("创建堆,初始化大小为1页,大小可变\n");
}
//判断堆是否创建/获取成功
if(hHeap == NULL)
{
   printf("创建或获取进程堆错误: %d",GetLastError());
   return 1;
}
//获取将打印当前进程中一共有多少个堆,有没有新建堆,值会不同
dwHeapNum = GetProcessHeaps(24,hHeaps);
if(dwHeapNum == 0)
{
   printf("GetProcessHeaps error: %d",GetLastError());
}
else
{
   printf("当前进程一共有%d个堆\n",dwHeapNum);
}
//在堆上分析内存,3个页面大小
lpMem = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,si.dwPageSize*3);
if(lpMem == NULL)
{
   printf("HeapAlloc error: %d",GetLastError());
   return 1;
}
printf("在堆上成功分配内存,起始地址为:0x%x\n",lpMem);
//打印当前堆内存块的大小
PrintHeapSize(hHeap,lpMem);
//再分配内存,调整内存的大小为11个分页大小,
//如果使用第一种方法创建堆,这里会出错
lpReAlloc = HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, lpMem, si.dwPageSize*11);
if(lpReAlloc == NULL)
{
   printf("HeapReAlloc error: %d",GetLastError());
   return 1;
}
printf("在堆上再分配内存,地址为:0x%x,原地址:0x%x\n",lpReAlloc,lpMem);
//打印调整大小后的堆内存块大小
PrintHeapSize(hHeap,lpReAlloc);

//释放内存
if(!HeapFree( hHeap, HEAP_NO_SERIALIZE, lpReAlloc))
{
   printf("HeapFree error: %d",GetLastError());
   return 1;
}
printf("释放内存成功\n");
//如果新建了堆,销毁堆。
if(argc != 2 || 0!=lstrcmp(argv[1],"-s"))
{
   printf("销毁HeapCreate创建的堆\n");
   if(!HeapDestroy(hHeap))
   {
    printf("HeapDestroy error: %d",GetLastError());
    return 1;
   }
   printf("销毁堆成功\n");
}
return 0;
}