关于内存映射,Linux中提供了mmap API,非常简单好用。
关于mmap和内存映射的理论知识,如下:
都22年了,还有人不懂mmap内存映射详解?
面试和工作中可能会用到mmap内存映射
以上两篇文章中,也有Linux mmap的使用方法。
这篇文章记录一下,windows中VC++如何进行内存映射。
1.通过CreateFileAPI打开一个文件,并指定权限。
2.通过CreateFileMapping创建一个内存映射对象。
3.通过MapViewOfFile映射共享内存地址
4.步骤1和2中的返回HANDLE需要通过CloseHandle结束。
与Linux中mmap(),munmap()相比,稍显复杂。
准备一个文本文件,mmap_file.txt,编码格式为ANSI。
在其中输入26个英文字母,此时它的大小是26字节。
创建一个控制台工程,为了简单,使用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;
}
在以上代码中把权限修改为只读:
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);
再次运行
执行了 *mem = '1';
后,在CloseHandle时,会抛出异常。
注释掉 *mem = '1';
可以正常结束。
注释掉后的运行结果,没有任何修改:
来源: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 操作。