关于 Windows 用户空间内存分配限制的问题

Question about Windows userspace memory allocation limits

我正在尝试查看我可以在 Windows 中分配内存的最大地址。我通过使用 GetSystemInfo 获得最大地址,然后尝试分配一个 4KB 页面。我注意到一些我以前从未见过的行为,我想知道是否有人可以解释为什么会这样。首先,这是我的测试代码:

SYSTEM_INFO info;
GetSystemInfo(&info);

PVOID base = (PUCHAR)info.lpMaximumApplicationAddress - info.dwPageSize;
SIZE_T size = info.dwPageSize;

LPVOID mem = VirtualAlloc(base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

以下是我注意到的几件事。

  1. 分配的大小实际上大于一页的4KB,是64KB。为什么?
  2. 分配的基地址是0x7ffffffe0000。对于 64KB 的分配大小,结束地址为 7fffffff0000,仅比最高用户地址多一个字节。这不是越界吗?

我正在 x64 上执行此操作 Windows。

如果我能理解为什么会这样,那就太好了。

The size of the allocation is actually larger than the 4KB for one page, it's 64KB. Why?

您没有考虑 info.dwAllocationGranularity。页大小可能是4K,但是粒度是64K。页面分配必须是粒度的偶数倍。因此,您指定的基地址将向下舍入到下一个最低粒度边界。 VirtualAlloc() 文档对此进行了讨论:

lpAddress

The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary. To determine the size of a page and the allocation granularity on the host computer, use the GetSystemInfo function. If this parameter is NULL, the system determines where to allocate the region.

另见 Why is address space allocation granularity 64K?

在您的情况下,info.lpMaximumApplicationAddress 很可能 0x7FFFFFEFFFF(比 8TB 少 64K,这是 Windows 8 及更早版本支持的最大内存;Windows 8.1 颠簸限制为 128TB)。从中减去 4K 是 0x7FFFFFEEFFF,然后向下舍入为 0x7FFFFFF0000,它是 64K 的偶数倍。

The base address of the allocation is 0x7ffffffe0000. With a 64KB allocation size, the end address is 7fffffff0000 which is just one byte more than the highest user address. Isn't this going out of bounds?

info.lpMaximumApplicationAddress 的作用类似于数组的 1-past-the-end 指针,或标准 C++ 容器的 end() 迭代器。这是一个你不应该超过的最大地址,甚至是取消引用。您可以访问内存地址 最大地址,但不包括它。