MapViewOfFileEx - 有效的lpBaseAddress

时间:2012-08-25 12:11:11

标签: winapi memory memory-management

在回答有关将非连续文件块映射到连续内存here的问题时,一位受访者建议我应该使用VirtualAllocEx()和MEM_RESERVE来建立一个MapViewOfFileEx()的最终(lpBaseAddress)参数的'safe'值。

进一步调查显示,此方法导致MapViewofFileEx()失败,错误487:“尝试访问无效地址”。 The MSDN page says

  

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

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

在网络上,我找到了带有硬编码值的示例 - example

#define BASE_MEM     (VOID*)0x01000000

...

hMap = MapViewOfFileEx( hFile, FILE_MAP_WRITE, 0, 0, 0, BASE_MEM );

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

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

3 个答案:

答案 0 :(得分:2)

你几乎已经自己解决了这个问题,但没有达到最后一小步。 如您所知,使用VirtualAlloc(使用MEM_RESERVE)在您的地址空间中查找空间,但之后(在MapViewOfFileEx之前)使用VirtualFreeMEM_RELEASE })。现在地址范围将再次免费。然后使用相同的内存地址(由VirtualAlloc返回)和MapViewOfFileEx

答案 1 :(得分:0)

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

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

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

来自MSDN

  

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

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

此外:

  

如果lpBaseAddress参数指定了基本偏移量,则如果调用进程尚未使用指定的内存区域,则该函数会成功。系统无法确保在其他32位进程中可用于内存映射文件的相同内存区域。

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

所以直接回答你的问题:

  

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

不,没有。并非没有对运行时环境应用许多约束(例如,限制到特定版本的OS,设置所有DLL的基地址,禁止DLL注入等)。

答案 2 :(得分:0)

你要做的事情是不可能的。

MapViewOfFileEx docs开始,您提供的指针是“指向映射开始的调用进程地址空间中的内存地址的指针。这必须是系统内存分配粒度的倍数,否则函数将失败。 “

memory allocation granularity is 64K,因此您无法将不同的4K页面从文件映射到虚拟内存中的相邻4K页面。