【问题标题】:Question about Windows userspace memory allocation limits关于Windows用户空间内存分配限制的问题
【发布时间】:2021-04-30 19:06:35
【问题描述】:

我正在尝试查看在 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 上执行此操作。

如果我能理解为什么会发生这种情况,那就太好了。

【问题讨论】:

    标签: c windows winapi virtual-memory


    【解决方案1】:

    分配的大小实际上大于一页的 4KB,它是 64KB。为什么?

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

    lpAddress

    要分配的区域的起始地址。如果内存被保留,指定的地址将向下舍入到分配粒度的最接近的倍数。如果内存已被保留并正在提交,则地址向下舍入到下一页边界。要确定页面大小和主机上的分配粒度,请使用GetSystemInfo 函数。如果该参数为NULL,则系统决定分配区域的位置。

    另见Why is address space allocation granularity 64K?

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

    分配的基地址是0x7ffffffe0000。分配大小为 64KB 时,结束地址为 7fffffff0000,仅比最高用户地址多一个字节。这不是越界了吗?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-30
      • 2018-05-22
      • 2021-08-27
      • 2011-03-24
      • 1970-01-01
      • 2011-11-29
      • 2012-02-03
      • 1970-01-01
      相关资源
      最近更新 更多