MMAP使用(一、基本接口)

提问:

  1. mmap是什么?有什么用?
  2. mmap的接口怎么使用?每个参数又有什么作用?

回答:

1.mmap是什么?有什么用?

  1. mmap将一个文件或者其它对象映射进内存。mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap,mmap的实现和硬件有关。
  2. 两个进程可以通过映射普通文件实现共享内存通信。
  3. 在网络下载中,可以通过映射整个文件,使文件减少一次从内核态到用户态的拷贝,从而加快传输的效率。

2.mmap的接口怎么使用?每个参数又有什么作用?

mmap的建立

#include<sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

mmap()系统调用在调用进程的虚拟地址空间中创建一个新的映射。
成功返回映射首地址,这地址分页对齐,失败返回MAP_FAILED(在Linux实现上等同于(void*)-1)。

参数addr指定了映射被放置的虚拟地址。首选做法是将addr指定为NULL,内核会为映射选择一个合适的地址。
        将addr指定为非NULL,内核会将该参数值作为一个提示信息来处理。

参数length指定了映射字节数。如果length不是分页的整数倍,内核会以分页大小为单位建立映射。
         因此,length实际上会被向上提升为分页大小的下一个倍数。

参数prot和参数flags在MMAP使用二中介绍。这里只介绍它们的用处。
参数prot是一个位掩码,指定了新内存映射上的保护信息。
参数flags是一个控制映射操作各个方面的选项的位掩码。只能选一个。

(匿名映射会忽略下面两个参数)
参数fd表示映射的文件的文件描述符。

参数offset指定了映射在文件中的起点,必须是系统分页大小的倍数。

解除映射区域:munmap()

#include<sys/mman.h>

int munmap(void *addr, size_t length);

成功返回0,失败返回-1.
参数addr是待解除映射地址范围的起始地址,它必须与一个分页边界对齐。
参数length是一个非负整数,指定了待解除映射区域的大小(字节数)。
        范围为系统分页大小的下一个倍数的地址空间将会被解除映射。
  • 一般来讲,通常会解除整个映射。因此可以将addr指定为上一个mmap()调用返回的地址,并且length值与mmap()调用中使用的length值一样。
int fd = open(fileName, O_RDWR | O_CREAT, 0666);
if(-1 == fd)
{
    perror("open");
    return -1;
}
int length = 1;
char *addr = (char*)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if(addr == MAP_FAILED)
{
    perror("mmap");
    return -1;
}

if(munmap(addr, length) == -1)
{
    perror("munmap");
    return -1;
}

 

同步映射区域:msync()

int msync(void *addr, size_t length, int flags);

让应用程序能够显式地控制何时完成共享映射与映射文件之间的同步。
这是非常有用的。如为确保数据完整性。
成功返回0,失败返回-1.
传给msync()的addr和length参数指定了需同步的内存区域的起始地址和大小。
在addr中指定的地址必须是分页对齐的,length会向上舍入到系统分页的下一个整数倍大小。

参数flags可取值为下列值中的一个:
MS_SYNC: 执行一个同步的文件写入。这个调用会阻塞直到内存区域中所有被修改过的分页被写入到底盘为止。
MS_ASYNC:执行一个异步的文件写入。内存区域中被修改过的分页会在后面某个时刻被写入磁盘并立即对在相应文件区域中执行read()
的其他进程可见。

flags参数中还可以加上下面这个值。
MS_INVALIDATE:使映射数据的缓存副本失效。
当内存区域中所有被修改过的分页被同步到文件中之后,内存区域中所有与底层文件不一致的分页会被标记为无效。
当下次引用这些分页会从文件的相应位置处复制相应的分页内容。
其结果是其他进程对文件作出的所有更新将会在内存区域中可见。

3.Mmap使用细节

  1. mmap中参数length大小可以超过文件大小,当然无论超不超过都会提升至系统页的整数倍大小。但是如果写入的内容超过了文件大小,超过部分不会写入文件。这时候就需要配合ftruncate或者lseek对文件进行偏移(相关概念:文件空洞)。代码如下:(文件在一开始只有6B的空间,如果不配合ftruncate或者lseek,后面"is null"不会写入文件中)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

### MMAP 操作的使用方法及常见问题解决方案 #### 什么是 MMAPMMAP种将文件或其他对象映射到内存的技术,允许程序通过访问内存的方式直接操作文件内容。这种方式可以显著提升读写性能,尤其是在处理大文件时。 --- #### 如何在不同编程语言中使用 MMAP? ##### Go 中的 MMAP 使用 `mmap-go` 提供了个可移植的 MMAP 实现[^1]。以下是其基本用法: ```go package main import ( "fmt" "log" "github.com/gh_mirrors/mm/mmap-go" ) func main() { filePath := "example.txt" // 文件路径 mmappedFile, err := mmap.Map(filePath, mmap.RDONLY) // 只读方式打开文件 if err != nil { log.Fatalf("无法映射文件: %v", err) } defer mmappedFile.Unmap() fmt.Println(string(mmappedFile)) } ``` 上述代码展示了如何将个文件映射到内存并打印其内容。需要注意的是,在完成操作后应调用 `Unmap()` 方法释放资源。 --- ##### C++ 中的 MMAP 使用 在 C++ 中,通常会结合 GCC 编译器和标准库实现 MMAP 功能[^3]。以下是个简单的例子: ```cpp #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <iostream> int main() { const char* filePath = "example.txt"; // 文件路径 int fd = open(filePath, O_RDONLY); // 打开只读文件描述符 if (fd == -1) { std::cerr << "无法打开文件\n"; return 1; } off_t length = lseek(fd, 0, SEEK_END); void* addr = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { close(fd); std::cerr << "mmap 失败\n"; return 1; } std::cout.write(static_cast<char*>(addr), length); // 输出文件内容 munmap(addr, length); // 映射解除 close(fd); // 关闭文件描述符 } ``` 此代码片段演示了如何利用 POSIX 的 `mmap` 函数将文件映射到内存,并安全地清理资源。 --- ##### Python 中的 MMAP 使用 Python 自带 `mmap` 模块支持类似的内存映射功能。下面是段示例代码: ```python import mmap import os file_path = 'example.txt' # 文件路径 with open(file_path, 'r+b') as f: map_file = mmap.mmap(f.fileno(), 0) # 将整个文件映射到内存 print(map_file.readline()) # 逐行读取 map_file.close() ``` 该脚本说明了如何加载文件并通过内存映射接口对其进行操作。 --- #### 常见问题及其解决方案 1. **分配器冲突** 如果在某些环境中启用了多个分配器(如 Xbyak 和其他自定义分配器),可能会引发冲突。可以通过宏控制是否启用特定分配器[^2]: ```cpp #define XBYAK_USE_MMAP_ALLOCATOR ``` 或者禁用它以避免干扰: ```cpp #define XBYAK_DONT_USE_MMAP_ALLOCATOR ``` 2. **异常处理机制** 当发生错误时,可能需要捕获异常以便更好地调试或恢复状态。例如,在反序列化过程中可能出现数据损坏的情况[^4]: ```go h, err := mph.Read(bytes.NewReader(data)) if err != nil { log.Fatalf("反序列化失败: %v", err) } ``` 3. **编译链接问题** 在构建基于 MMAP 的应用程序时,确保正确指定依赖项。比如对于 C++ 程序,需显式链接标准库: ```bash gcc myfirst.cpp -lstdc++ gcc mem_map.cpp mmap_w.cpp -o mmap_w -lstdc++ ``` 4. **跨平台兼容性** 不同操作系统对 MMAP 的实现略有差异。因此建议测试目标环境下的行为致性。例如,Windows 下不完全遵循 POSIX 标准,则需要额外适配逻辑。 --- #### 总结 无论是哪种语言框架下实施 MMAP 技术都需要关注细节配置以及潜在风险规避措施;合理运用工具链能够极大简化开发流程同时增强应用表现力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值