第十五章 应用虚拟内存
1.在地址空间内保留一块区域(地址空间)
LPVOID WINAPI VirtualAlloc(
__in LPVOID lpAddress,//指定区域的首地址 (地址值为64KB的整数倍)
__in SIZE_T dwSize, //区域的大小(字节数) 4KB的整数倍
__in DWORD flAllocationType,//分配方式:Reserve|Commit|Reset MEM_TOP_DOWN|MEM_LARGE_PAGES
__in DWORD flProtect //设置保护属性
);
(1)若lpAddress为NULL, 系统会在进程空间中找到一块合适区域,然后将该区域的地址返回
(2)若想指定区域的首地址, 则需将首地址的值赋给lpAddress
系统会自动将该值切割成64KB的整数倍,如:我们想在19,668,992 (300 × 65,536 + 8192)处保留一块区域
系统会把19,668,992切割成19,660,800 (300 × 65,536). 然后在该地址处保留一块区域并返回该值(19,660,800)。
(3) MEM_TOP_DOWN 在高地址处分配空间
lpAddress为NULL,系统可能在进程空间的任意部分保留一块区域。若该区域是在进程的地址空间的中部,则有可能会产生内存碎片。
为了避免内存碎片的产生 尤其是当我们想常时间保留一块区域时,我们可以通过设定MEM_TOP_DOWN,让系统尽可能的在高地址处保留一块区域。
2.交付会把实际的物理存储空间分配给保留的区域。
我们可以在保留一块区域的同时来交付这块区域。也可以先保留,等需要时再交付这块区域。
当需要分配大量内存时,如果CPU支持“大分页分配”,可以用MEM_LARGE_PAGE 和 GetLargePageMinimum来增加分页大小,提高分配内存的性能。
在做大分页分配时有以下两点需要注意:
(1)大分页分配的内存是unpageable的,只能存在于RAM中,不会存在Page file中
(2)用户必而具有Lock Memory的权限。
更多信息查阅MSDN by keyword:Large Page Support
3.何时交付内存
适时的交付内存可以提高内存的使用效率,避免分配不必要的内存导致内存资源浪费。
判断何时分配内存的最好方法是SHE(Structured Exception Handling),详见第二十五章
4.解除交付和释放保留区域
Decommitting Physical Storage and Releasing a Region
BOOL VirtualFree(
LPVOID pvAddress,
SIZE_T dwSize,
DWORD fdwFreeType
);
(1)释放保留区域 release a region
当释放保留区域时,我们必须释放整个保留的区域,该交付给该区域会被释放掉。试图访问已释放的区域会导致异常。
(2)解除交付
仅释放内存,但该区域仍处于保留状态。我们可以仅解除一部分区域而不必像“释放保留区域”那样解除整个区域
解除交付也是以分页为单位的。dwSize指定了要释放的大小(以字节为单位)。
若大小不够一页按一页算。
例:3KB,那么系统会解除交付 pvAddress~pvAddress+4KB空间内的内存。
5KB,那么系统会解除交付 pvAddress~pvAddress+8KB空间内的内存。
5改变保护属性
BOOL VirtualProtect(
PVOID pvAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD pflOldProtect
);
我们在保留地址空间时要指定区域的保护的属性。
通过VirtualProtect函数我们可以动态地改变区域中某些分页的保护属性
6.Reset物理存储的内容
Reset的用途是告诉系统指定的区域的内容没有改变,不需要将该区域的内容写到页文件中。
以便使这块区域长期存放在RAM,以便再用到该区域时不需要换页操作。
7.Common API:
GetLargePageMinimum