我正在尝试使用VirtualAlloc保留并提交一块内存,然后再次扩展该块。 不幸的是,尽pipeVirtualQuery说请求的地址范围是空闲的,但它仍然返回NULL,错误为ERROR_INVALID_ADDRESS。 这是我的代码:
void* allocation = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); void* desiredNextAllocation = (char*)allocation + 4096; MEMORY_BASIC_INFORMATION info; size_t memory_info = VirtualQuery(desiredNextAllocation, &info, sizeof(info)); void* extended = VirtualAlloc(desiredNextAllocation, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
第一个分配返回0x00000000000d0000。 对VirtualQuery的调用会在'info'中产生以下数据:
BaseAddress 0x00000000000d1000 void * AllocationBase 0x0000000000000000 void * AllocationProtect 0x00000000 unsigned long RegionSize 0x00000000000ff000 unsigned __int64 State 0x00010000 unsigned long Protect 0x00000001 unsigned long Type 0x00000000 unsigned long
我认为这意味着有0xff可用的页面从0xd1000开始,处于MEM_FREE状态。 那么为什么我试图提交页面0xd1000失败?
我正在运行Windows 7,这是一个64位版本。
我已经阅读了几个关于VirtualAlloc的StackOverflow的post,但是他们似乎都暗示这个代码应该和我对文档的理解一样。
从VirtualAlloc的文档 :
如果内存被保留,则指定的地址向下舍入到分配粒度的最接近的倍数。
在这种情况下,地址0xd1000向下舍入为地址0xd0000,该地址已被保留,因此无效。
如果要指定连续的页面进行分配,则需要将分配内存的地址空间分开分配。 牢记这一点,我们可以实现这样的代码:
#include <windows.h> #include <iostream> #include <iomanip> std::ostream &operator<<(std::ostream &os, MEMORY_BASIC_INFORMATION const &mi) { return os << std::setw(20) << "Allocation Base: " << mi.AllocationBase << "\n" << std::setw(20) << "BaseAddress: " << mi.BaseAddress << "\n" << std::setw(20) << "Protection: " << mi.Protect << "\n" << std::setw(20) << "Region size: " << mi.RegionSize; } void show_page(void *page) { MEMORY_BASIC_INFORMATION info; VirtualQuery(page, &info, sizeof(info)); std::cout << info << "\n\n"; } static const int page_size = 4096; void *alloc_page(char *address) { void *ret = VirtualAlloc(address, page_size, MEM_COMMIT, PAGE_READWRITE); show_page(ret); return ret; } int main() { static const int region_size = 65536; char * alloc = static_cast<char *>(VirtualAlloc(NULL, region_size, MEM_RESERVE, PAGE_READWRITE)); for (int i = 0; i < 4; i++) alloc_page(alloc + page_size * i); }
示例结果:
Allocation Base: 00000000000C0000 BaseAddress: 00000000000C0000 Protection: 4 Region size: 4096 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C1000 Protection: 4 Region size: 4096 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C2000 Protection: 4 Region size: 4096 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C3000 Protection: 4 Region size: 4096
正如你所看到的,所有的分配现在都成功了。 另外:当你保留地址空间时,你可以分配的最小的大小是64K(如上所示)。 您应该通过调用GetSystemInfo
,并使用它提供的SYSTEM_INFO
结构中的dwPageSize
和dwAllocationGranularity
来真正获取页面大小和最小区域大小。