VirtualAlloc 失败
VirtualAlloc failing
我正在尝试使用 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);
第一次分配returns0x00000000000d0000。对 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
我将其解释为从 0xd1000 开始有 0xff 个可用页面处于 MEM_FREE 状态。那么,为什么我尝试提交 0xd1000 页面会失败?
我是 运行 Windows 7,这是一个 64 位版本。
我已经阅读了几篇关于 VirtualAlloc 的 Whosebug 帖子,但它们似乎都暗示这段代码应该像我对文档的理解一样工作。
如果要为分配指定连续的页面,则需要将分配地址 space 与分配内存分开以支持它。牢记这一点,我们可以实现这样的代码:
#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
如您所见,现在所有分配都成功了。顺便说一句:当您保留地址 space 时,您可以分配的最小大小是 64K(如上所示)。您实际上应该通过调用 GetSystemInfo
并在它给您的 SYSTEM_INFO
结构中使用 dwPageSize
和 dwAllocationGranularity
来获得页面大小和最小区域大小。
来自documentation for VirtualAlloc:
If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity.
在这种情况下,地址 0xd1000 向下舍入为地址 0xd0000,该地址已被保留,因此无效。
我正在尝试使用 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);
第一次分配returns0x00000000000d0000。对 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
我将其解释为从 0xd1000 开始有 0xff 个可用页面处于 MEM_FREE 状态。那么,为什么我尝试提交 0xd1000 页面会失败?
我是 运行 Windows 7,这是一个 64 位版本。
我已经阅读了几篇关于 VirtualAlloc 的 Whosebug 帖子,但它们似乎都暗示这段代码应该像我对文档的理解一样工作。
如果要为分配指定连续的页面,则需要将分配地址 space 与分配内存分开以支持它。牢记这一点,我们可以实现这样的代码:
#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
如您所见,现在所有分配都成功了。顺便说一句:当您保留地址 space 时,您可以分配的最小大小是 64K(如上所示)。您实际上应该通过调用 GetSystemInfo
并在它给您的 SYSTEM_INFO
结构中使用 dwPageSize
和 dwAllocationGranularity
来获得页面大小和最小区域大小。
来自documentation for VirtualAlloc:
If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity.
在这种情况下,地址 0xd1000 向下舍入为地址 0xd0000,该地址已被保留,因此无效。