在VirtualAlloc中对齐内存

Mic*_*man 5 winapi virtual-memory

作为Win64上某些代码的优化,我保留了4GB的地址空间,然后在该地址空间内提交了一定数量的MB(例如512MB)(最终通过数组绑定检查删除提供了巨大的性能提升,但这一切都在点).我的代码基本上是这样的:

LPVOID address = VirtualAlloc(null, FOUR_GB, MEM_RESERVE, PAGE_NOACCESS);
arrayAddress = VirtualAlloc(address, length, MEM_COMMIT, PAGE_READWRITE);
Run Code Online (Sandbox Code Playgroud)

我团队中的某个人最近阅读了一篇关于大页面需要较少TLB查找并且在某些情况下性能显着提高的论文,这似乎是尝试这一点的主要候选者.

但是,我正在阅读的内容让我觉得这可能不起作用.MSDN说"大小和对齐必须是大页面最小值的倍数".我可以很容易地确保长度是大页面最小值的倍数,但是我如何才能进行对齐?如果我可以将MEM_LARGE_PAGES标志传递给预留,我认为这将正确对齐它.但我已经读过你不能用MEM_RESERVE | MEM_LARGE_PAGES调用VirtualAlloc.

所以我的想法是我可以做我现在正在做的事情,但是在预订期间使用FOUR_GB + GetLargePageMinimum()进行VirtualAlloc,然后在提交时将地址与GetLargePageMinimum()对齐,但这对我来说感觉不对.

有谁知道正确的方法呢?

小智 1

是的,使用大(或巨)页将显着降低 TLB 压力,从而提高内存访问性能。我们在 SCADA 软件中使用它可以带来巨大的好处。SQL Server 也是如此。

Windows 上的大页面是不可分页的,即始终锁定在内存中。无法保留,只能完全承诺。锁定页面是特殊特权操作,通常不会为计算机上的任何帐户(甚至 SYSTEM)配置SeLockMemoryPrivilege 。尽管如此,它还是可以添加启用的

然后这将起作用:

VirtualAlloc (NULL, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
Run Code Online (Sandbox Code Playgroud)

您不必担心巨大的 (1GB) 页面。如果可能,Windows(1607+、Server 2016+)将在您请求足够的 2MB 且可用时为您分配一个。

您不必担心对齐问题,您会将它们对齐到 2MB(或 1GB)。

但您可以使用自 Windows 10 版本 1803(RS4,内部版本 17134)和 Server 2019 起可用的VirtualAlloc2 API来请求 1GB 页面和额外对齐,如下所示:

MEM_ADDRESS_REQUIREMENTS requirement;
requirement.LowestStartingAddress = NULL;
requirement.HighestEndingAddress = NULL;
requirement.Alignment = 4 * 1024 * 1024 * 1024; // align to 4GB boundary

MEM_EXTENDED_PARAMETER xp[2];
xp[0].Type = MemExtendedParameterAddressRequirements;
xp[0].Pointer = &requirement;

xp[1].Type = MemExtendedParameterAttributeFlags;
xp[1].ULong64 = MEM_EXTENDED_PARAMETER_NONPAGED_HUGE; // 1GB pages required

VirtualAlloc2 (NULL, NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, xp, 2);
Run Code Online (Sandbox Code Playgroud)