linux内核mmap原理

本文详细介绍了内存映射机制,包括mmap系统调用的过程及其实现原理。从虚拟地址到物理地址的映射通过内核中的do_mmap_pgoff和mmap_region函数实现,并最终通过remap_pfn_range配置页目录表项来完成。文章还解释了页帧号(pfn)的概念及其与MMU映射表的关系。

应用空间

返回一段映射好的虚拟地址,操作这个虚拟地址就能操作到设备的物理地址

void * mmap(void *start,size_t length,int port,int flags,int fd,offset)

系统调用syscall

内核

do_mmap_pgoff 
     mmap_region //在当前的进程空间分配一个mmap区域,分配一个struct vm_area_struct对象,mmap区域的长度为PAGE大小的整数倍
         file->f_op->mmap(file,vma) //将分配的mmap区域映射到设备的内存上
             remap_pfn_range(vma,addr,pfn,size,prot)//需要完成页目录表项的配置
remap_pfn_range(vma,addr,pfn,size,prot)
//将参数addr起始大小为size的虚拟地址空间映射到pfn表示的一组的连续的物理页面上
//pfn为物理地址的页帧号,在页面大小为4kb的系统中,一个物理地址右移12位可以得到,与mmu映射表有关系
//port 页表中的属性位,比如cache
### Linux mmap 函数的工作原理 `mmap` 是 Linux 系统中用于内存映射文件的系统调用。它允许将一个文件或设备直接映射到进程的地址空间,从而实现高效的文件访问和修改操作[^1]。其函数原型为: ```c void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` - `addr`:指定映射区域的起始地址。通常设置为 `nullptr`,让内核选择合适的地址。 - `length`:指定映射区域的大小(以字节为单位)。 - `prot`:指定映射区域的保护权限,例如 `PROT_READ`(可读)、`PROT_WRITE`(可写)、`PROT_EXEC`(可执行)等。 - `flags`:指定映射的类型和行为,例如 `MAP_SHARED`(共享映射)或 `MAP_PRIVATE`(私有映射)。 - `fd`:文件描述符,指向要映射的文件。 - `offset`:文件中开始映射的偏移量,必须是页大小的整数倍。 当成功调用时,`mmap` 返回一个指向映射区域的指针;如果失败,则返回特殊值 `MAP_FAILED`[^2]。 #### 工作机制 1. **内存映射**:`mmap` 将文件内容直接映射到进程的虚拟地址空间,使得对文件的操作可以通过简单的内存访问完成,避免了传统的 I/O 操作中的多次数据拷贝。 2. **按需加载**:只有在访问映射区域时,数据才会从磁盘加载到内存中,这种机制称为“延迟加载”或“按需分页”。 3. **共享与私有**: - 在 `MAP_SHARED` 模式下,对映射区域的修改会直接反映到文件中,并且这些修改对其他进程可见。 - 在 `MAP_PRIVATE` 模式下,对映射区域的修改不会影响原始文件,而是通过“写时复制”机制创建新的页面。 #### 使用场景 1. **大文件处理**:对于需要频繁访问的大文件,使用 `mmap` 可以显著提高性能,因为它减少了用户空间和内核空间之间的数据拷贝次数。 2. **进程间通信**:通过将同一段文件映射到多个进程的地址空间,可以实现高效的进程间通信。 3. **动态链接库**:操作系统通常使用 `mmap` 加载动态链接库到内存中。 4. **零拷贝技术**:结合 `mmap` 和网络 I/O,可以实现零拷贝的数据传输,减少 CPU 和内存的开销。 以下是一个简单的代码示例,展示如何使用 `mmap` 对文件进行写入操作[^3]: ```c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <unistd.h> #include <sys/mman.h> #define SIZE 4096 int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " filename" << std::endl; return 1; } std::string filename = argv[1]; int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0666); if (fd < 0) { std::cerr << "open failed!!!" << std::endl; return 2; } ::ftruncate(fd, SIZE); // 设置文件大小 char *mmap_addr = (char *)::mmap(nullptr, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mmap_addr == MAP_FAILED) { perror("mmap error"); return 3; } for (int i = 0; i < SIZE; i++) { mmap_addr[i] = 'a' + i % 26; } ::munmap(mmap_addr, SIZE); // 取消映射 ::close(fd); // 关闭文件 return 0; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值