导读:本期聚焦于小伙伴创作的《c++怎么释放被映射的文件内存_UnmapViewOfFile安全调用【实战】》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《c++怎么释放被映射的文件内存_UnmapViewOfFile安全调用【实战】》有用,将其分享出去将是对创作者最好的鼓励。

在c++开发中,文件映射是一种高效的文件读写方式,它可以将磁盘文件直接映射到进程的虚拟地址空间,避免频繁的磁盘IO操作。但使用文件映射后,必须正确释放映射的内存,否则会导致内存泄漏甚至程序异常,其中UnmapViewOfFile是释放映射视图的核心函数。

c++怎么释放被映射的文件内存_UnmapViewOfFile安全调用【实战】

文件映射的基本使用流程

在使用UnmapViewOfFile之前,需要先了解完整的文件映射创建流程,通常分为以下几个步骤:

  • 调用CreateFile打开目标文件,获取文件句柄
  • 调用CreateFileMapping创建文件映射对象,获取映射对象句柄
  • 调用MapViewOfFile将映射对象映射到进程地址空间,获取映射内存的指针
  • 使用映射的内存进行读写操作
  • 操作完成后调用UnmapViewOfFile释放映射视图,再依次关闭映射对象句柄和文件句柄

UnmapViewOfFile函数说明

UnmapViewOfFile是Windows API提供的函数,用于取消文件映射视图与进程地址空间的映射关系,函数原型如下:

// 函数原型
BOOL UnmapViewOfFile(
  LPCVOID lpBaseAddress // 映射视图的起始地址,即MapViewOfFile返回的指针
);

函数调用成功返回非零值,失败返回零,可以通过GetLastError获取错误码。需要注意的是,传入的lpBaseAddress必须是之前MapViewOfFile调用成功返回的地址,否则调用会失败。

UnmapViewOfFile安全调用实战

1. 基础安全调用示例

下面是一个完整的文件映射创建、使用、释放的示例代码,展示UnmapViewOfFile的正确调用方式:

#include <windows.h>
#include <iostream>

int main() {
    // 1. 打开文件
    HANDLE hFile = CreateFile(
        L"test.txt",               // 文件路径
        GENERIC_READ | GENERIC_WRITE, // 读写权限
        0,                          // 不共享
        NULL,                       // 默认安全属性
        OPEN_EXISTING,              // 文件必须存在
        FILE_ATTRIBUTE_NORMAL,      // 普通文件属性
        NULL                        // 无模板文件
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cout << "打开文件失败,错误码:" << GetLastError() << std::endl;
        return 1;
    }

    // 2. 创建文件映射对象
    HANDLE hMapFile = CreateFileMapping(
        hFile,                      // 文件句柄
        NULL,                       // 默认安全属性
        PAGE_READWRITE,             // 可读可写
        0,                          // 映射大小高32位,0表示使用文件实际大小
        0,                          // 映射大小低32位,0表示使用文件实际大小
        NULL                        // 映射对象名称,不需要则设为NULL
    );
    if (hMapFile == NULL) {
        std::cout << "创建文件映射对象失败,错误码:" << GetLastError() << std::endl;
        CloseHandle(hFile); // 释放文件句柄
        return 1;
    }

    // 3. 映射视图到进程地址空间
    LPVOID pMapView = MapViewOfFile(
        hMapFile,                   // 映射对象句柄
        FILE_MAP_ALL_ACCESS,        // 所有访问权限
        0,                          // 文件偏移高32位
        0,                          // 文件偏移低32位,从文件开头开始映射
        0                           // 映射字节数,0表示映射整个文件
    );
    if (pMapView == NULL) {
        std::cout << "映射视图失败,错误码:" << GetLastError() << std::endl;
        CloseHandle(hMapFile); // 释放映射对象句柄
        CloseHandle(hFile);    // 释放文件句柄
        return 1;
    }

    // 4. 使用映射的内存,这里示例写入数据
    char* pData = (char*)pMapView;
    strcpy_s(pData, 100, "这是通过文件映射写入的测试数据");

    // 5. 安全释放映射视图
    BOOL unmapResult = UnmapViewOfFile(pMapView);
    if (unmapResult == 0) {
        std::cout << "释放映射视图失败,错误码:" << GetLastError() << std::endl;
    } else {
        std::cout << "释放映射视图成功" << std::endl;
        pMapView = NULL; // 释放后将指针置为NULL,避免野指针
    }

    // 6. 依次关闭映射对象句柄和文件句柄
    CloseHandle(hMapFile);
    CloseHandle(hFile);

    return 0;
}

2. 常见错误与规避方法

在实际开发中,调用UnmapViewOfFile容易出现以下错误,需要特别注意:

  • 重复调用UnmapViewOfFile:同一个映射视图指针只能调用一次UnmapViewOfFile,重复调用会导致未定义行为,建议在调用后将指针置为NULL,后续调用前先判断指针是否为NULL。
  • 传入错误的地址:如果传入的地址不是MapViewOfFile返回的地址,或者地址已经被释放过,调用会失败,需要确保传入的地址是有效的映射视图起始地址。
  • 忽略返回值:UnmapViewOfFile调用失败后不会抛出异常,需要主动检查返回值,根据错误码排查问题,比如错误码为ERROR_INVALID_ADDRESS表示传入的地址无效。
  • 未关闭相关句柄:UnmapViewOfFile只是释放映射视图,还需要依次关闭文件映射对象句柄和文件句柄,否则会导致资源泄漏。

3. 异常处理场景下的安全调用

如果在使用映射内存的过程中可能发生异常,需要确保在异常发生时也能正确释放映射视图,示例代码如下:

#include <windows.h>
#include <iostream>

void SafeFileMappingDemo() {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE hMapFile = NULL;
    LPVOID pMapView = NULL;

    try {
        // 打开文件
        hFile = CreateFile(L"test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            throw GetLastError();
        }

        // 创建映射对象
        hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
        if (hMapFile == NULL) {
            throw GetLastError();
        }

        // 映射视图
        pMapView = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (pMapView == NULL) {
            throw GetLastError();
        }

        // 模拟业务逻辑,可能抛出异常
        // ...

        // 正常释放
        UnmapViewOfFile(pMapView);
        pMapView = NULL;
    } catch (DWORD errorCode) {
        std::cout << "发生异常,错误码:" << errorCode << std::endl;
        // 异常时释放资源
        if (pMapView != NULL) {
            UnmapViewOfFile(pMapView);
            pMapView = NULL;
        }
    }

    // 释放句柄
    if (hMapFile != NULL) {
        CloseHandle(hMapFile);
    }
    if (hFile != INVALID_HANDLE_VALUE) {
        CloseHandle(hFile);
    }
}

注意事项

除了正确调用UnmapViewOfFile之外,还需要注意以下几点:

  • 如果映射的内存被多个进程共享,一个进程调用UnmapViewOfFile只会释放当前进程的映射视图,不会影响其他进程的映射。
  • 调用UnmapViewOfFile之后,之前指向映射内存的指针会变为无效,不能再对其进行读写操作,否则会导致访问违规。
  • 如果文件映射对象还有其他的映射视图没有被释放,关闭映射对象句柄不会立即销毁映射对象,直到所有映射视图都被释放。

UnmapViewOfFile文件映射内存释放c_plus_plus修改时间:2026-07-10 19:48:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。