MapViewOfFileEx - 有效的lpBaseAddress

aSt*_*eve 5 memory winapi memory-management

在回答有关将非连续文件块映射到连续内存的问题时,在这里,一位受访者建议我应该使用带有MEM_RESERVE的VirtualAllocEx()来为最终(lpBaseAddress)参数建立一个"安全"值对于MapViewOfFileEx().

进一步的调查显示,这种方法导致MapViewofFileEx()失败,错误487:"尝试访问无效地址". MSDN页面说:

"在用于映射的区域中不能进行其他内存分配,包括使用VirtualAlloc或VirtualAllocEx函数来保留内存."

尽管对于有效的调用序列,文档可能被认为是模糊的,但实验表明使用VirtualAllocEx()为MapViewOfFileEx()保留内存是无效的.

在网络上,我发现了带有硬编码值的示例 - 例如:

#define BASE_MEM     (VOID*)0x01000000
Run Code Online (Sandbox Code Playgroud)

...

hMap = MapViewOfFileEx( hFile, FILE_MAP_WRITE, 0, 0, 0, BASE_MEM );
Run Code Online (Sandbox Code Playgroud)

对我而言,这似乎是不充分和不可靠的...我很清楚为什么这个地址是安全的,或者可以安全地在那里映射多少块.考虑到我需要我的解决方案在其他分配的上下文中工作,它似乎更加不稳定......而且我需要我的源代码来编译和工作在32位和64位上下文中.

我想知道的是,是否有任何方法可靠地保留地址空间池,以便 - 随后 - MapViewOfFileEx可以可靠地将其映射到显式内存地址.

Adr*_*thy 0

如果您提供基地址,该函数将尝试将您的文件映射到该地址。如果它无法使用该基地址(因为某些东西已经使用了所请求的内存区域的全部或部分),则调用将失败。

对于大多数应用程序来说,尝试自己修复地址没有任何实际意义。如果您是一个复杂的数据库进程,并且出于效率原因尝试在具有已知配置的计算机上仔细管理自己的内存布局,那么这可能是合理的。但你必须做好失败的准备。

在 64 位进程中,虚拟地址空间是相当开放的,因此可以确定地选择基地址,但我认为我不会打扰。

来自MSDN

虽然可以指定现在安全的地址(操作系统未使用),但不能保证该地址随着时间的推移将保持安全。因此,最好让操作系统选择地址。

我相信“随着时间的推移”是指操作系统的未来版本以及您正在使用的任何运行时库(例如,用于内存分配),这可能会采用不同的内存布局方法。

还:

如果 lpBaseAddress 参数指定基址偏移量,并且指定的内存区域尚未被调用进程使用,则该函数将成功。系统不确保相同的内存区域可用于其他 32 位进程中的内存映射文件。

所以基本上,您的直觉是正确的:指定基地址是不可靠的。你可以尝试,但你必须做好失败的准备。

那么直接回答你的问题:

我想知道的是,是否有任何方法可以可靠地保留地址空间池,以便随后 MapViewOfFileEx 可以可靠地使用它来将块映射到显式内存地址。

不,没有。并非没有对运行时环境施加许多限制(例如,限制到操作系统的特定版本、为所有 DLL 设置基地址、禁止 DLL 注入等)。