每次在C#中运行程序时如何使用相同的虚拟内存块

时间:2014-05-16 13:40:48

标签: c# memory dll memory-address

我有一个用C#编写的程序,它使用外部DLL。我在Windows 7 64bit上。此DLL需要内存中160MB的连续块。基本上,我在这个DLL中调用一个函数,它在调用我传递给它的回调函数时确实工作了很长时间。启动此过程的DLL函数的一个参数是进程将尝试使用的整数内存地址。 DLL负责内存分配,它只需要160MB内存,你可以选择传入这个内存块的起始地址(如果你想让库本身找到它,则为0)。

如果我将0作为参数传递,它可以正常工作,因为库本身可以找到内存。但是为了利用这个库的某些功能,我需要能够在每次启动新进程时将此DLL传递给相同的内存地址(并且可以并行运行多个相同的进程)。

鉴于Windows程序有自己的虚拟地址空间,我如何确保该库能够在所有进程中使用相同的160MB虚拟内存块?即使我编写的应用程序有一个确定性的启动过程,我发现使用一个特定的内存地址(例如0xABC00000)可能会工作几次,但然后在第三个失败,因为DLL无法在那里分配内存,因为它已经被使用过。

很抱歉这个问题很长,我希望这能说清楚我要做的事情。我只是不知道如何确保在同一进程的多次运行之间C#中的外部DLL可以使用相同寻址的内存块。谢谢!

2 个答案:

答案 0 :(得分:1)

首先,让我回顾一下虚拟地址空间的概念。

每个地址空间都可以访问虚拟地址,例如,让我们谈谈虚拟地址0x001000到0x24000。

地址空间1具有这些地址以及地址空间2等。但是,地址空间1的实际物理存储可能是0x091000到0x2D0000,而地址空间2的相同虚拟地址被映射到物理地址0x011000到0x25000。

到目前为止,在本说明书中,两个地址空间不可能共享相同的物理存储。但是,每个地址空间都可以访问" global"每个地址空间在物理上相同的地址。

因此,浏览MSDN(Microsoft开发人员网络)并扫描" atom"和/或"全球地址"等等。您应该能够找到允许您分配可供其他进程使用的全局存储的Microsoft调用。如果您无法找到此信息。在MSDN上,请回复我,我会进行搜索。

答案 1 :(得分:0)

我意识到在我弄清楚之后,我再也没有回过头来回答这个问题。事实证明,使用 kernel32.dll 中的 VirtualAlloc 功能非常简单。

在我的情况下,我需要在每次打开程序时为外部进程保留相同的虚拟地址(或者在每个进程中,如果同时运行多个副本)。所以我所做的基本上是选择一个虚拟地址并将其硬编码到程序中。这样,外部进程总是能够使用相同的虚拟地址内存块:

[DllImport("kernel32", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType lAllocationType, MemoryProtection flProtect);

// use same virtual address in all processes
const uint reserveAddress = 0x00CF0000;

// reserve 160MB at that address immediately at the start of the program
VirtualAlloc(new IntPtr(reserveAddress), new UIntPtr(160*1024*1024), AllocationType.RESERVE, MemoryProtection.EXECUTE_READWRITE);

// now just pass that same address to my external process when needed
int result = StartExternalProcess(reserveAddress);

这对我有用,并且外部进程能够在每次启动程序时将其保存状态重新加载到相同的内存位置。确保这是一个不寻常的要求,但这是我使用的第三方库的要求。我希望在类似的情况下帮助其他人。