我正在尝试使用VirtualAlloc来保留和提交一块内存,然后再次扩展该块。不幸的是,尽管VirtualQuery声称所请求的地址范围是空闲的,但它返回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帖子,但他们似乎都暗示这段代码应该像我对文档的理解一样工作。
答案 0 :(得分:4)
如果要为分配指定连续页面,则需要将分配地址空间与分配内存分开以备份它。记住这一点,我们可以实现类似这样的代码:
epw-title
示例结果:
#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);
}
如您所见,所有分配现在都成功了。另外:当您保留地址空间时,您可以分配的最小大小为64K(如上所示)。您应该通过调用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
,并使用GetSystemInfo
结构中的dwPageSize
和dwAllocationGranularity
来获取页面大小和最小区域大小。
答案 1 :(得分:1)
来自documentation for VirtualAlloc:
如果正在保留内存,则将指定的地址向下舍入到分配粒度的最接近的倍数。
在这种情况下,地址0xd1000向下舍入到地址0xd0000,该地址已被保留,因此无效。