虚拟内存分配(VirtualAlloc)的基本用法和注意事项是什么?
VirtualAlloc?
VC声明
LPVOID VirtualAlloc(
LPVOID lpAddress, // region to reserve or commit
SIZE_T dwSize, // size of region
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);
[编辑本段]
说明
该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页
如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0;
[编辑本段]
参数表说明
LPVOID lpAddress, 分配内存区域的地址。当你使用VirtualAlloc来提交一块以前保留的内存块的时候,lpAddress参数可以用来识别以前保留的内存块。如果这个参数是NULL,系统将会决定分配内存区域的位置,并且按64-KB向上取整(roundup)。
SIZE_T dwSize, 要分配或者保留的区域的大小。这个参数以字节为单位,而不是页,系统会根据这个大小一直分配到下页的边界DWORD
flAllocationType, 分配类型 ,你可以指定或者合并以下标志:MEM_COMMIT,MEM_AUTO_COMMIT,MEM_RESERVE和MEM_TOP_DOWN。
DWORD flProtect 指定了被分配区域的访问保护方式
分配类型 功能
MEM_COMMIT 在内存或者指定的磁盘页文件(虚拟内存文件)中分配一物理存储区域 函数初始化这个区域为0
MEM_PHYSICAL 该类型必须和MEM_RESERVE一起使用 分配一块具有读写功能的物理内存区
MEM_RESERVE 保留虚拟地址空间以便以后提交。
MEM_RESET
MEM_TOP_DOWN 告诉系统从最高可允许的虚拟地址开始映射应用程序。
MEM_WRITE_WATCH
访问类型
PAGE_READONLY 该区域为只读。如果应用程序试图访问区域中的页的时候,将会被拒绝访问PAGE_READWRITE 区域可被应用程序读写
PAGE_EXECUTE 区域包含可被系统执行的代码。试图读写该区域的操作将被拒绝。
PAGE_EXECUTE_READ 区域包含可执行代码,应用程序可以读该区域。
PAGE_EXECUTE_READWRITE 区域包含可执行代码,应用程序可以读写该区域。
PAGE_GUARD 区域第一次被访问时进入一个STATUS_GUARD_PAGE异常,这个标志要和其他保护标志合并使用,表明区域被第一次访问的权限
PAGE_NOACCESS 任何访问该区域的操作将被拒绝
PAGE_NOCACHE RAM中的页映射到该区域时将不会被微处理器缓存(cached)
注:PAGE_GUARD和PAGE_NOCHACHE标志可以和其他标志合并使用以进一步指定页的特征。PAGE_GUARD标志指定了一个防护页(guard page),即当一个页被提交时会因第一次被访问而产生一个one-shot异常,接着取得指定的访问权限。PAGE_NOCACHE防止当它映射到虚拟页的时候被微处理器缓存。这个标志方便设备驱动使用直接内存访问方式(DMA)来共享内存块。
[编辑本段]
返回值
如果调用成功,返回分配的首地址,
调用失败,返回NULL 你可以通过GetLastError函数来获取错误信息
[编辑本段]
笔记
VirtualAlloc可以通过并行多次调用提交一个区域的部分或全部来保留一个大的内存区域。多重调用提交同一块区域不会引起失败。这使得一个应用程序保留内存后可以随意提交将被写的页。当这种方式不在有效的时候,它会释放应用程序通过检测被保留页的状态看它是否在提交调用之前已经被提交
例子:
#include
void main()
{
SYSTEM_INFO sf;
GetSystemInfo(&sf);
//分配内存,标记为提交、可读可写
LPVOID lpvBase = VirtualAlloc(
NULL, // system selects address
4096, // size of allocation
MEM_COMMIT, // allocate reserved pages
PAGE_READWRITE); // protection = no access
if (lpvBase == NULL )
return;
//向该内存里面写些东西
unsigned char *ustr=(unsigned char *)lpvBase;
ustr[0]=0x89;
//修改为“只读”属性,验证是否能写入
DWORD dw;
VirtualProtect(lpvBase,4096,PAGE_READONLY,&dw);
// ustr[0]=0x44; //失败
//修改为“不可访问”,验证是否能读出
VirtualProtect(lpvBase,4096,PAGE_NOACCESS,&dw);
// dw = ustr[0]; //失败
return;
}