mmap内存映射

时间:2023-03-09 09:01:26
mmap内存映射

http://blog.****.net/kongdefei5000/article/details/70183119

内存映射是个很有用,也很有意思的思想。我们都知道操作系统分为用户态和内核态,用户态是不能直接和物理设备打交道的,如果想把硬盘的一块区域读到用户态,则需要两次拷贝(硬盘->内核->用户),但是内存映射的设计只需要发生一次的拷贝,大大的提高了读取数据的效率。那么内存映射的原理和内核是如何实现的呢?

因为内存映射涉及到虚拟内存的管理,虚拟内存到物理内存的映射,因此在详细介绍内存映射前先普及(回忆)一下相关的概念。

CPU的架构

目前CPU架构主要分为三种:SMP, NUMA, MPP,详细的介绍参考CPU架构。这里主要关注MMU和TLB在CPU中的角色和位置。 
mmap内存映射 
上图是Intel的i7处理器一个核的架构图,图中可以看出每一个CPU核都已一个自己的MMU和TLB。

Linux进程和线程

关于Linux进程和线程的话题想必大家都不陌生,这也是面试时候经常被问到的问题,后续我会专门写一篇博文介绍Linux线程和进程的区别,已经内核是如何实现的。这里我们只需要知道下面几个概念即可: 
* 操作系统本身也是一个进程 
* 操作系统内核层面没有线程的概念,只有进程的概念,因此线程在内核看来也是一个进程,只是比较特殊 
* 线程的实现是glibc实现的(pthread),包括创建,管理等

虚拟地址

虚拟地址是面向进程的一套虚拟内存的地址,为了更好的管理内存,并且能够保证内存对程序员而言是透明的,也就是写程序的时候对每一个程序来说都是一样的地址空间,因此提出了虚拟内存的概念,对应的就是虚拟地址。这里我们不关注具体的细节,为了后面的讲解,我们简单的了解一下虚拟内存在内核层面是怎么进行管理的。 
mmap内存映射
这张图右侧的进程虚拟器对于每一个进程都是一样的,就是上面说的虚拟空间,然后对于进程,内核对每一个进程都维护了一个task_struch的结构,其中有三个重要的成员,pgd指向改进程的页表首地址,然后mmap和mm_rb都是用来管理vm的结构,vm是虚拟内存管理的基本单元,含有内存的类型,起始和结束地址,mmap是线性表实现的,mm_rb则使用红黑树进行管理,分别适用不同的场景。

MMU

MMU(Memory Management Unit),内存管理单元,主要负责CPU内存访问的时候将虚拟地址转换为物理地址的单元。也就是说CPU想要访问内存必须先经过MMU的转换,获得真正的物理地址,才能读写物理内存的数据。其实MMU只是一个简单的计算单元,它通过虚拟地址查找页表,找到对应的物理地址,然后返回给CPU。在查找页表的过程中可能发生多次的物理内存访问,这取决于系统采用页表管理系统是几级的,目前Linux的页表是四级的,因此需要查询四次页表,每一次查询都会获得一个物理地址指向下一级页表的内存地址,知道最后获得实际要访问的内存物理地址。 
mmap内存映射 
从图中可以看出,当CPU得到一个虚拟地址去访问内存的时候会先将虚拟地址发送到MMU(1),然后MMU会先从TLB查询是否存在这个虚拟地址到物理地址的缓存,如果存在则直接返回给CPU,如果没有则会根据虚拟地址讲过计算获得物理内存中页表项的地址然后读取得到PTE(Linux可能要读取四次),PTE就是物理内存地址或者硬盘存储地址。然后MMU会将该PTE缓存在TLB中,最后使用这个物理地址再次访问物理内存或者硬盘地址获得要访问的内容。

内存映射

mmap

基础知识介绍完毕,那么到底什么是内存映射呢,映射让我们不禁都会想起数学上的映射关系,是的就是那个意思,这里是讲设备或者硬盘存储的一块空间映射到物理内存,然后操作这块物理内存就是在操作实际的硬盘空间,不需要经过内核态传递。比如你的硬盘上有一个文件,你可以使用linux系统提供的mmap接口,讲这个文件映射到进程一块虚拟地址空间,这块空间会对应一块物理内存,当你读写这块物理空间的时候,就是在读取实际的磁盘文件,就是这么直接,这么高效。通常诸如共享库的加载都是通过内存映射的方式加载到物理内存的。

mmap本身其实是一个很简单的操作,在进程的页表中添加一个页表项,该页表项是物理内存的地址。调用mmap的时候,内核会在改进程的虚拟空间的映射区域查找一块满足需求的空间用于映射该文件,然后生成该虚拟地址的页表项,改页表项此时的有效位(标志是否已经在物理内存中)为0,页表项的内容是文件的磁盘地址,此时mmap的任务已经完成。 
mmap内存映射 
当mmap建立完页表的映射后,就可以操作改块内存了,进行的所有改动都会自动写会磁盘文件。第一次访问该块内存的时候,因为页表项的有效位还是0,就会发生缺页中断,然后CPU会使用该页表项的内容也就是磁盘的文件地址,讲该地址指向的内容加载到物理内存,并需改页表项的内容为该物理地址,有效位置为1. 
mmap内存映射

munmap

有映射必然有解除映射,系统提供了一个munmap的接口去解除指定地址的映射关系。munmap主要的功能是清除页表项,解除这个映射关系,但是这个过程中会涉及到缓存的刷新,虚拟内存vm的删除,TLB的一致性(tlb shootdown操作),这里就不再详细讲解。

附件:内存映射

原文地址:http://kdf5000.com/2017/02/17/mmap内存映射/