学习内容:
一、内存映射原理
二、数据结构
三、系统调用
一、内存映射原理
【物理内存】
物理地址是处理器在系统总线上看到的地址。使用RISC的处理器通常只实现一个物理地址空间,外围设备和物理内存使用统一的物理地址空间。有些处理器架构把分配给外围设备的物理地址区域称为设备内存。
处理器通过外围设备控制器的寄存器访问外围设备,寄存器分为控制寄存器,状态寄存器和数据寄存器三大类。外围设备的寄存器通常被连续编址,处理器对外围谁被寄存编址方式分为两种:I/O映射方式(I/O-mapped),内存映射方式(memory-mapped)。
I/O映射方式:inter X86处理为外围设备的一个专用实现一个单独的地址空间,这个地址空间可以称为I/O地址空间或者I/O单口空间。处理器通过专门的处理指令,如IN OUT这些指令来访问这个空间当中的地址单元。
内存映射方式:使用RISC(精简指令器),处理器实现一个物理地址空间,外围设备和物理内存使用统一的物理地址空间,处理器可以像访问一个内存单元的方式去访问一个外围设备,不需要提供一个专门的I/O指令。
应用程序只能通过虚拟地址访问外设寄存器,内核提供API函数来把外设寄存器的物理地址映射到虚拟地址空间。
ARM64架构(物理地址宽度最大支持48位)分为两种内存类型:
正常内存(Normal Memory):包括物理内存和只读存储器(ROM);
设备内存(Device Memory):指分配给外围设备寄存器的物理地址区域。
设备内存共享属性总是外部共享,缓存属性总是不可缓存(不许绕过处理器的缓存)。
两个进程可以使用共享的文件映射实现共享内存。匿名映射通常是私有映射,共享的匿名映射只可能出现在父进程和子进程之间。在进程的虚拟地址空间中,代码段和数据段是私有的文件映射,未初始化数据段、堆栈是私有的匿名映射。
修改后的脏页面不会立刻更新到文件中,可以调用msync来强制同步写入文件。
【内存映射原理】
创建内存映射的时候,在晋城的用户虚拟地址空间中分配一个虚拟内存区域。内核采用延迟分配物理内存的策略,在进程第一次访问虚拟页的时候,产生缺页异常。如果是文件映射,那么分配物理页,把文件制定区间的数据读到物理页中,然后在页表中把虚拟页映射到物理页。如果是匿名映射,就分配物理页,然后在页表中把虚拟页映射到物理页。
内存映射是在进程的虚拟地址空间中创建一个映射,分为两种:
(1)文件映射:文件支持的内存映射,把文件的一个区间映射到进程的虚拟地址空间,数据源是存储设备上的文件。
(2)匿名映射:没有文件支持的内存映射,把物理内存映射到进程的虚拟地址空间,没有数据源。
二、数据结构
【数据结构】
虚拟内存区域分配给进程的一个虚拟地址范围,内核使用结构体vm_area_struct描述虚拟内存区域,主要核心成员:
虚拟内存区域struct vm_area_struct源码分析如下:
文件映射–虚拟内存区域如下图:
三、系统调用
内存管理子系统提供如下常用的系统调用函数:
1、mmap()——创建内存映射
#include <sys/mman.h>
void *mmap(void *addr , size_t length , int prot , int flags , int fd , off_t offset);
系统调用mmap():进程创建匿名的内存映射,把内存的物理页映射到进程的虚拟地址空间。进程把文件映射到进程的虚拟地址空间,可以像访问内存一样访问文件,不需要调用系统调用read()/write()访问文件,从而避免用户模式和内核模式之间的切换,提高读写文件速度。两个进程针对同一个文件创建共享的内存映射,实现共享内存。
2、munmap()——删除内存映射
#include <sys/mman.h>
int munmap(void *addr , size_t len);
3、mprotect()——设置虚拟内存区域的访问权限
#include <sys/mman.h>
int mprotect(void *addr , size_t len , int prot);
应用程序通常使用C标准库提供的函数malloc()申请内存。glibc库的内存分配器ptmalloc使用brk或mmap向内核以页为单位申请虚拟内存,然后把页划分成小内存块分配给应用程序。默认阈值是128KB,如果应用程序申请的内存长度小于阈值,ptmalloc分配器使用brk向内核申请虚拟内存,否则ptmalloc分配器使用mmap向内核申请虚拟内存。
应用程序可以直接使用mmap向内核申请虚拟内存。
回顾mmap内存映射原理三个阶段:
1、进程启动映射过程,并且在虚拟地址空间中为映射创建虚拟映射区域;
2、调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟的一一映射关系;
3、进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝。
操作实例1:使用两个进程通过映射普通文件实现共享内存通信
操作实例2:mprotect()设置虚拟内存区域的访问权限
操作实例比较麻烦,想了解更多可私聊