[内存] windows 实现内存映射

Linux中的mmap

关于内存映射,Linux中提供了mmap API,非常简单好用。
关于mmap和内存映射的理论知识,如下:
都22年了,还有人不懂mmap内存映射详解?
面试和工作中可能会用到mmap内存映射

以上两篇文章中,也有Linux mmap的使用方法。
这篇文章记录一下,windows中VC++如何进行内存映射。

Windows中的内存映射

Windows内存映射的步骤

1.通过CreateFileAPI打开一个文件,并指定权限。
2.通过CreateFileMapping创建一个内存映射对象。
3.通过MapViewOfFile映射共享内存地址
4.步骤1和2中的返回HANDLE需要通过CloseHandle结束。

与Linux中mmap(),munmap()相比,稍显复杂。

文件准备

准备一个文本文件,mmap_file.txt,编码格式为ANSI。
在其中输入26个英文字母,此时它的大小是26字节。

进行VC++内存映射

创建一个控制台工程,为了简单,使用MBCS工程,是工程中直接调用ANSI版本Windows API。

可读可写的共享内存

代码如下

#include 
#include 
#include 

#define INPUT_FILENAME "D:\\SourceCode\\mmap_file.txt"
int GetInputFileSize(const char* filepath);
int main()
{
    HANDLE c_dumpFileDescriptor;
    HANDLE c_fileMappingObject;
    //Get file length
    int filelength = 0;
    if ((filelength = (int)GetInputFileSize(INPUT_FILENAME)) == 0)
        return false;
    char err_str[256] = { 0x00 };

    c_dumpFileDescriptor = CreateFile(
        INPUT_FILENAME,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (c_dumpFileDescriptor == NULL) {
        std::cout << GetLastError() << std::endl;
    }
    c_fileMappingObject = CreateFileMapping(c_dumpFileDescriptor, NULL, PAGE_READWRITE, 0, 0, NULL);
    if (c_fileMappingObject == NULL) {
        std::cout << GetLastError() << std::endl;
    }
    void* mappedFileAddress = MapViewOfFile(c_fileMappingObject, FILE_MAP_ALL_ACCESS, 0, 0, filelength);
    if (!mappedFileAddress) {
        std::cout << GetLastError() << std::endl;
        return false;
    }
    
    //读取内存映射中的文件内容
    char* mem = (char*)mappedFileAddress;
    char  c_array[64] = { 0x00 };
    memcpy_s(c_array, sizeof(c_array), mem, filelength);
    std::cout << "read memory:" << c_array << std::endl;

    //修改内存映射中的内容,最后同步到文件
    *mem = '1';

    CloseHandle(c_fileMappingObject);
    CloseHandle(c_dumpFileDescriptor); 

}
//获取文件大小
int GetInputFileSize(const char* filepath)
{
    if (!strlen(filepath))
        return false;
    struct _stat64 statbuff;
    _stat64(filepath, &statbuff);
    return statbuff.st_size;
}

控制台输出结果
[内存] windows 实现内存映射_第1张图片
运行结束后查看文件,第一个字符被修改了
[内存] windows 实现内存映射_第2张图片

只读共享内存

在以上代码中把权限修改为只读:

before
    c_dumpFileDescriptor = CreateFile(
        INPUT_FILENAME,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
after
c_dumpFileDescriptor = CreateFile(
        INPUT_FILENAME,
        GENERIC_READ , // 这里权限改了
        FILE_SHARE_READ,  // 这里权限改了
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
before
c_fileMappingObject = CreateFileMapping(c_dumpFileDescriptor, NULL, PAGE_READWRITE, 0, 0, NULL);
after
c_fileMappingObject = CreateFileMapping(c_dumpFileDescriptor, NULL, PAGE_READONLY, 0, 0, NULL);  
before
void* mappedFileAddress = MapViewOfFile(c_fileMappingObject, FILE_MAP_ALL_ACCESS, 0, 0, filelength);
after
void* mappedFileAddress = MapViewOfFile(c_fileMappingObject, FILE_MAP_READ, 0, 0, filelength);

再次运行
[内存] windows 实现内存映射_第3张图片
执行了 *mem = '1';后,在CloseHandle时,会抛出异常。
注释掉 *mem = '1'; 可以正常结束。
注释掉后的运行结果,没有任何修改:
在这里插入图片描述
[内存] windows 实现内存映射_第4张图片

内存映射的基础问答

来源:MMAP 常见面试题

MMAP 是什么?它有什么用?

MMAP 是一种内存映射技术,可以将文件映射到进程的虚拟地址空间中,从而实现文件和内存之间的直接访问。它可以避免频繁的磁盘 I/O 操作,提高文件读写效率和性能。

MMAP 的优点和缺点是什么?

MMAP 的优点包括:

避免了频繁的磁盘 I/O 操作,提高了文件的读写效率和性能。
可以节省内存,只有在需要时才加载文件。
可以使得文件数据在多个进程之间共享。

MMAP 的缺点包括:

MMAP 需要大量的虚拟地址空间,可能会出现内存不足的情况。
MMAP 可能会对操作系统的缓存机制产生影响,影响其他进程的性能。
MMAP 不适合频繁修改的文件,其效率不如普通文件 I/O 操作。

MMAP 和 read/write 操作有什么区别?

read/write 操作是一种传统的文件读写方式,它需要将数据从文件读取到缓冲区中,或者将数据从缓冲区写入到文件中。而 MMAP 是一种将整个文件映射到进程的虚拟内存中,直接访问文件所在的内存区域的技术。
与 read/write 操作相比,MMAP 的优点是可以避免频繁的磁盘 I/O 操作,提升文件的读写效率和性能,同时由于数据是直接映射到进程地址空间中,所以可以实现跨进程共享数据。但是,MMAP 也有一些缺点,比如可能会出现内存不足的情况,不适合频繁修改的文件等。

MMAP 是如何工作的?

当使用 mmap 将一个文件映射到进程的地址空间中时,操作系统会将文件的一个区域缓存到内存中,然后将该内存区域映射到进程的地址空间中。当进程尝试访问该区域数据时,操作系统会自动将数据处理传输到磁盘文件中,从而避免了频繁的磁盘 I/O 操作。

你可能感兴趣的:(内存,windows,linux,c++)