Winapi MapViewOffilex-有效的lpBaseAddress

Winapi MapViewOffilex-有效的lpBaseAddress,winapi,memory,memory-management,Winapi,Memory,Memory Management,在回答一个关于将非连续文件块映射到连续内存的问题时,一位受访者建议我使用()和MEM_RESERVE,以便为()的最终(lpBaseAddress)参数建立一个“安全”值 进一步的调查显示,这种方法导致MapViewOffilex()失败,错误为487:“尝试访问无效地址。”: 在用于映射的区域中不能进行其他内存分配,包括使用VirtualAlloc或VirtualAllocEx函数来保留内存 虽然文档可能会被认为对有效的调用序列不明确,但实验表明,使用VirtualAllocEx()为MapV

在回答一个关于将非连续文件块映射到连续内存的问题时,一位受访者建议我使用()和MEM_RESERVE,以便为()的最终(lpBaseAddress)参数建立一个“安全”值

进一步的调查显示,这种方法导致MapViewOffilex()失败,错误为487:“尝试访问无效地址。”:

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

虽然文档可能会被认为对有效的调用序列不明确,但实验表明,使用VirtualAllocEx()为MapViewOffilex()保留内存是无效的

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

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


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

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

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

在64位进程中,虚拟地址空间是非常开放的,因此可以确定地选择一个基址,但我认为我不会费心

发件人:

虽然现在可以指定一个安全的地址(操作系统不使用),但不能保证该地址在一段时间内保持安全。因此,最好让操作系统选择地址

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

此外:

如果lpBaseAddress参数指定了一个基偏移量,则如果指定的内存区域尚未被调用进程使用,则函数将成功。系统无法确保其他32位进程中的内存映射文件具有相同的内存区域

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

因此,要直接回答您的问题:

我想知道的是,是否有任何方法可以可靠地保留一个地址空间池,以便MapViewOffilex能够可靠地使用它将块映射到显式内存地址


不,没有。如果不在运行时环境中应用许多约束(例如,限制特定版本的操作系统、为所有DLL设置基址、禁止DLL注入等),则无法执行此操作。

您尝试执行的操作是不可能的

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


这样,您就无法将文件中不同的4K页面映射到虚拟内存中相邻的4K页面。

您几乎自己找到了解决方案,但没有完成最后一小步。
如图所示,使用
VirtualAlloc
(使用
MEM\u RESERVE
)在地址空间中找到空间,但在此之后(在
mapViewofilex
之前)使用
VirtualFree
(使用
MEM\u RELEASE
)。现在,地址范围将再次空闲。然后将相同的内存地址(由
VirtualAlloc
返回)与
mapviewofilex
一起使用。“你们唯一能做的就是早点做。”汉斯,虽然我没有理由不相信你们,但我希望你们能提供一份明确的参考书来说明这一点。让VirtualAllocEx支持显式地址似乎很愚蠢,但无法可靠地保留地址空间。早期映射可能在某些上下文中有效,但不适用于多线程程序,在多线程程序中,不同的视图需要在进程生命周期中映射。明确的参考是MSDN文章,理解为您不喜欢它所说的内容。显然,当您无法控制分配虚拟内存的其他代码时,您不可能将视图可靠地映射到特定地址。因此,合乎逻辑的结论是,您不应该试图让它工作,而让操作系统来选择地址。MSDN并没有说没有可靠的方法来做到这一点——它只是说我不应该使用VirtualAlloc()。你说得对,我不喜欢上面说的。。。正如您所理解的那样,它使Windows下的内存映射比Linux/Unix下的灵活性大大降低。如果这是Windows不可避免的固有问题,我可以接受——但我强烈希望不是这样。一些文档假设在显式地址的映射是在共享内存的两个进程中的相同位置复制对象。我理解这一点,但我正在单个进程中映射内存文件,而不是实现共享内存。我还理解,“建议”允许操作系统在任何可能的情况下分配地址——但是,我注意到,如果需要映射非连续的blo,这是不可能的
#define BASE_MEM     (VOID*)0x01000000
hMap = MapViewOfFileEx( hFile, FILE_MAP_WRITE, 0, 0, 0, BASE_MEM );