云计算百科
云计算领域专业知识百科平台

共享内存的申请释放

内存底层申请两大方式

  • 私有内存 Private Memory:VirtualAlloc/VirtualAllocEx,物理页仅当前进程独占
  • 映射内存 Mapped Memory:CreateFileMapping,支持多进程共享同一块物理页,分为两种:
    ○ 匿名共享物理页(INVALID_HANDLE_VALUE,不绑定磁盘文件,用作 IPC 共享内存)
    ○ 文件映射(绑定磁盘文件,把文件内容映射到虚拟地址)
  • 核心 API 介绍

  • CreateFileMapping(创建文件映射内核对象)
  • HANDLE CreateFileMapping(
    HANDLE hFile, // INVALID_HANDLE_VALUE:不关联文件,直接申请内存
    LPSECURITY_ATTRIBUTES lpAttributes, // 安全属性,一般NULL
    DWORD flProtect, // 页面保护属性 PAGE_READWRITE / PAGE_READONLY / PAGE_WRITECOPY
    DWORD dwMaximumSizeHigh, // 偏移高32位,可填0
    DWORD dwMaximumSizeLow, // 偏移低32位,填共享内存总字节大小
    LPCTSTR lpName // 命名,用于跨进程打开使用;匿名则NULL
    );

    返回值:内核对象句柄
    ● 对象不存在:新建映射对象,返回有效句柄
    ● 对象已存在:依然返回句柄,GetLastError()==ERROR_ALREADY_EXISTS
    ● 失败返回NULL
    保护属性:
    ● PAGE_READONLY:只读
    ● PAGE_READWRITE:读写
    ● PAGE_WRITECOPY:写时复制
    2. MapViewOfFile(把物理页映射到当前进程虚拟地址)

    LPVOID MapViewOfFile(
    HANDLE hFileMappingObject, //文件映射内核对象句柄
    DWORD dwDesiredAccess, //FILE_MAP_READ / FILE_MAP_WRITE / FILE_MAP_ALL_ACCESS
    DWORD dwFileOffsetHigh, //偏移高32位,可填0
    DWORD dwFileOffsetLow, //偏移低32位,映射起始位置,若从映射对象最开头映射:填0
    SIZE_T dwNumberOfBytesToMap //需要映射的字节数,想映射整个映射对象:填0
    );

    权限规则:视图权限不能比底层映射对象权限更宽松
    底层 PAGE_READONLY,视图只能 FILE_MAP_READ,不能写
    3. OpenFileMapping(打开已存在的命名映射对象)
    专门用于第二个进程打开别的进程创建好的共享内存,配合名称lpName使用
    4. 资源释放顺序(非常重要)

  • UnmapViewOfFile(pBuf):先解除当前进程虚拟地址映射
  • CloseHandle(hMapFile):关闭文件映射内核对象句柄
    内核对象采用引用计数,所有进程全部 CloseHandle 之后,内核对象才销毁
  • 共享内存原理

    多个进程各自的虚拟地址,可以通过页表指向同一份物理页
    ● 进程 A:0x390000 → 物理页 P
    ● 进程 B:0x520000 → 物理页 P
    ● A 写入数据,B 立刻读到,零拷贝,IPC 通信里性能最高
    ⚠️ 共享内存本身不带同步机制,多进程同时读写会出现竞态,需要手动加锁(互斥体 / 事件等内核对象)

    完整示例代码

    进程A:创建共享内存:
    #define MapFileName L"共享内存"
    #define BUFSIZ 4096
    HANDLE g_hMapFile = CreateFileMapping(
    INVALID_HANDLE_VALUE,
    NULL,
    PAGE_READWRITE,
    0,
    BUFSIZ,
    MapFileName);

    LPTSTR g_pBuf = (LPTSTR)MapViewOfFile(
    g_hMapFile,
    FILE_MAP_ALL_ACCESS,
    0,0,BUFSIZ);

    *(PDWORD)g_pBuf = 0x12345678; //写入测试数据
    // 使用完毕释放
    UnmapViewOfFile(g_pBuf);
    CloseHandle(g_hMapFile);

    进程B:打开同一块共享内存:
    HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,L"共享内存");
    LPVOID pBuf = MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,BUFSIZ);
    DWORD val = *(PDWORD)pBuf; //读取0x12345678
    UnmapViewOfFile(pBuf);
    CloseHandle(hMap);

    VAD 调试观察

    WinDbg 命令 !vad
    ● 共享内存区域标记为 Mapped
    ● 私有内存(栈、堆)标记为Private

    总结

  • CreateFileMapping 创建内核对象;MapViewOfFile 建立虚拟地址和物理页的映射
  • 两种用途:①磁盘文件映射;②匿名共享内存(IPC 跨进程通信,hFile=INVALID_HANDLE_VALUE)
  • 权限双层控制:底层映射对象保护属性 + MapViewOfFile 视图访问权限,取严格者生效
  • 释放顺序:先 UnmapViewOfFile,再 CloseHandle
  • 共享内存高性能,但无内置同步,需要互斥体 / 事件做并发保护
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » 共享内存的申请释放
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!