You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用VirtualAlloc实现跨进程固定基址共享内存的异常问题

跨进程指定地址共享内存的解决方案

嘿,这个问题的核心在于Windows每个进程的虚拟地址空间是完全独立的——你在第一个进程里用VirtualAlloc分配的0x80000000地址,只属于进程1自己的地址空间,进程2的这个地址区域默认是未映射的空白区域,直接访问当然会触发内存异常啦。

要实现两个进程在同一个虚拟地址访问共享内存,你得把CreateFileMapping(创建共享内存对象)和MapViewOfFileEx(带指定地址映射的版本)结合起来用,具体步骤如下:

步骤1:第一个进程(创建共享内存并映射到指定地址)

先创建一个命名的共享内存对象,然后把它映射到你想要的0x80000000地址:

// 创建共享内存文件映射对象
HANDLE hSharedMap = CreateFileMapping(
    INVALID_HANDLE_VALUE,    // 用系统分页文件做后备存储
    NULL,                    // 默认安全设置
    PAGE_READWRITE,          // 共享内存的读写权限
    0,                       // 内存大小高32位(这里设0,64KB用低32位足够)
    65536,                   // 共享内存大小:64KB
    L"FixedAddrSharedMem"    // 共享内存的唯一名称,别和系统里的重名
);

if (hSharedMap == NULL) {
    // 处理创建失败的情况,比如调用GetLastError()查原因
    return 1;
}

// 将共享内存映射到指定的0x80000000地址
LPVOID pMappedAddr = MapViewOfFileEx(
    hSharedMap,              // 刚才创建的共享内存句柄
    FILE_MAP_ALL_ACCESS,     // 读写访问权限
    0,                       // 文件偏移高32位(共享内存不用偏移,设0)
    0,                       // 文件偏移低32位
    65536,                   // 要映射的大小
    (LPVOID)0x80000000LL     // 关键!指定要映射到的虚拟地址
);

if (pMappedAddr == NULL) {
    // 映射失败,比如这个地址在进程1里已经被占用了
    CloseHandle(hSharedMap);
    return 1;
}

// 现在你就可以直接用0x80000000地址读写共享内存了

步骤2:第二个进程(打开共享内存并映射到相同地址)

在第二个进程里,打开同一个共享内存对象,然后同样用MapViewOfFileEx映射到0x80000000:

// 打开已存在的共享内存对象
HANDLE hSharedMap = OpenFileMapping(
    FILE_MAP_ALL_ACCESS,     // 和进程1一致的读写权限
    FALSE,                   // 不继承句柄
    L"FixedAddrSharedMem"    // 必须和进程1的共享内存名称完全一致
);

if (hSharedMap == NULL) {
    // 打开失败,比如共享内存还没创建,或者权限不够
    return 1;
}

// 映射到同一个0x80000000地址
LPVOID pMappedAddr = MapViewOfFileEx(
    hSharedMap,
    FILE_MAP_ALL_ACCESS,
    0,
    0,
    65536,
    (LPVOID)0x80000000LL
);

if (pMappedAddr == NULL) {
    // 映射失败,比如进程2的这个地址已经被其他内存占用了
    CloseHandle(hSharedMap);
    return 1;
}

// 现在你可以直接访问0x80000000了,不会再触发内存异常
char c = *((const char*)0x80000000LL);

几个关键注意事项

  • 必须用MapViewOfFileEx:普通的MapViewOfFile不能指定映射地址,只有带Ex的版本支持这个功能。
  • 地址必须在两个进程中都空闲:如果进程2的0x80000000地址已经被其他内存块占用,MapViewOfFileEx会调用失败。这时候你可以先在进程2里用VirtualAlloc((LPVOID)0x80000000LL, 65536, MEM_RESERVE, PAGE_NOACCESS)预留这个地址,再进行映射。
  • 权限要统一:两个进程的共享内存访问权限要保持一致,比如都用FILE_MAP_ALL_ACCESS,避免权限不足的问题。

为什么你之前的方法行不通?

你在进程1里用VirtualAlloc分配的是进程私有内存,这块内存只属于进程1,进程2完全看不到它。只有通过CreateFileMapping创建的共享内存对象,才是系统级别的共享资源,能被多个进程访问;再通过MapViewOfFileEx指定相同地址映射,才能让两个进程在同一个虚拟地址上操作这块共享内存。

内容的提问来源于stack exchange,提问作者thfabian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:48:29