《Linux虚拟内存管理基础v2》由会员分享,可在线阅读,更多相关《Linux虚拟内存管理基础v2(22页珍藏版)》请在金锄头文库上搜索。
1、1主要内容主要内容1.虚拟内存管理的基本原理和基本过程。2.CPU对虚拟内存管理的支持。(ULKCh.2)3.Linux如何管理页表。(ULKCh.2)4.Linux如何管理物理内存(ULKCh.8)5.Linux如何管理虚拟空间的内核地址空间部分(ULKCh.8)6.Linux如何管理虚拟空间的进程地址空间部分(ULKCh.9)7.Linux如何在物理内存和外出之间同步数据(ULKCh.15)8.Linux如何主动回收物理内存(ULKCh.17)注:无法全部讲骚瑞2从宏观角度从宏观角度.Linux的虚拟内存管理机制为应用程序和驱动的虚拟内存管理机制为应用程序和驱动程序程序提供了两种服务:提供
2、了两种服务:使每个进程都拥有自己独立的内存地址空间;对于使每个进程都拥有自己独立的内存地址空间;对于32位位Linux而言,每个任务可寻址的内存地址空间而言,每个任务可寻址的内存地址空间都为都为0x000000000xFFFFFFFF(232,4GB)当物理内存不够当物理内存不够4GB时,虚拟内存管理模块会用外时,虚拟内存管理模块会用外存空间模拟内存空间,并且该模拟过程对应用程序存空间模拟内存空间,并且该模拟过程对应用程序是透明的。是透明的。3用户地址空间与内核地址空间用户地址空间与内核地址空间1.Linux将每个进程的4GB的独立地址空间又划分为用户地址空间(0x000000000xBFFF
3、FFFF)和内核地址空间(0xC00000000xFFFFFFFF)两部分。2.操作系统内核代码和数据存放在内核地址空间;每个进程自己私有的代码和数据存放在用户地址空间3.虽然Linux的内核代码和数据被映射到了每个进程的地址空间中(所有进程看到的内容是相同的),但在实际的物理内存中,只有内核代码和数据的一份拷贝。4用户地址空间与内核地址空间用户地址空间与内核地址空间用户态与核心态用户态与核心态一般现代CPU都有几种不同的指令执行级别在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态用户态指相应的低级别执行状态,代码的掌控范围会受到限制,只能执行CPU指
4、令集的一个子集举例:intelx86CPU有四种不同的执行级别0-3,Linux只使用了其中的0级和3级分别来表示内核态和用户态0xc0000000以上的内核地址空间只能在内核态下访问,0x000000000xbfffffff的用户地址空间在两种状态下都可以访问应用程序可以通过Linux系统调用由用户态进入内核态6逻辑地址与物理地址逻辑地址与物理地址1.逻辑地址:程序在运行过程中用来访问存储器的地址。程序员在编程时,只需知道逻辑地址,不需考虑该地址与实际物理硬件上的存储单元如何对应。编译器在编译源程序时,也只需考虑逻辑地址。2.物理地址:表示物理存储器中一个存储单元的实际位置,地址总线上产生的
5、就是物理地址。(总线地址)3.在实地址模式下,逻辑地址等于物理地址。在虚拟地址模式下,逻辑地址不等于物理地址,必须经过查表才能转换为物理地址,因此也叫虚拟地址。4.线性地址:2维逻辑地址变为1维地址后,叫线性地址物理地址查表转换逻辑地址虚拟页虚拟页物理页物理页0 03 31 1nullnull2 21 13 3nullnull虚拟页虚拟页物理页物理页0 02 21 1nullnull2 21 13 3nullnull虚拟页虚拟页物理页物理页0 0nullnull1 1nullnull2 21 13 3nullnull物理页物理页takentaken进程进程idid0 0N Nnullnull1
6、 1Y Yosos2 2Y Y2 23 3Y Y1 1进程1的页表进程进程idid虚拟页虚拟页硬盘文件名硬盘文件名偏移量偏移量进程2的页表进程3的页表内页表外页表CR3寄存器CPU负责查表(虚拟地址-物理地址),查表失败时触发缺页异常(14号);OS负责填充各个表的内容,并提供缺页中断的中断服务器程序。8X86处理器对处理器对VM的支持的支持1.MMU单元:(1)自动查表,将当期指令中的逻辑地址转化为物理地址;(2)触发缺页异常。2.32bitCPU支持2级页表:页目录表,页表。10+10+123.64bitCPU支持4级页表:9+9+9+9+124.专用寄存器CR3中存放了当前有效的页目录表
7、的物理地址。5.专用寄存器CR2用于存放触发缺页异常的线性地址。6.转换旁视缓冲区TLB:将常用的逻辑/物理转换关系缓存到CPU。当页表被修改,或有效页表切换时需调用专用指令刷新TLB。flush_tlb_all,flush_tlb_mm,flush_tlb_range,flush_tlb_page932bitIntelx86的页表的页表1.在32位CPU上,地址空间为232,一个内存页大小为212,则共有220个页,页编号范围0220-1,因此页表中的一行至少要用3个字节(存储页编号是必须的),但实际上页表中一行占4个字节。2.80386CPU中一个页表项的定义如下:Present标志、Ac
8、cessed标志、Dirty标志、Read/Write标志、User/Supervisor标志、如果present标志为0,分页单元就把这个线性地址存放在处理器的CR2寄存器中,并产生一个14号缺页异常10页表项或页目录项中的标志页表项或页目录项中的标志1.Present标志:所指内容是否存在2.Accessded标志:所指内容被访问之后自动置13.Dirty标志:所指内容被修改后自动置14.Read/Write标志:所指内容的读写权限5.User/Supervisor标志:所指内容的访问特权要求6.PCD/PWT:是否运行被缓存至Cache7.PageSize:页大小:4K,4M,2M8.G
9、lobal标志:防止页从TLB中刷新出去11两级页表两级页表1.为了节省内存,32位CPU采用了两级页表2.第一级为页目录,每个表项存储了第二级页表的物理地址。3.第二级页表的每个表项存储了一个虚拟页所对应物理页的物理地址。4.32位的虚拟地址被分成3个域目录(directory)最高的10位页表(Table)中间的10位页内偏移量(offset)最低的12位5.程序中每产生一个32位的虚拟地址,CPU的MMU首先用最高的10位查页目录获得第二级页表的物理地址,再用中间10位查第二级页表获得物理页的起始地址,最后用该起始地址加上偏移量offset(最低的12位)就得到了最终的物理地址。6.两次
10、查表过程有可能会触发2次缺页中断。2024/7/25LinuxOSAnalysis12/54Intel80x86处理器的分页线性地址线性地址CR3页目录页目录页表页表页页2024/7/25LinuxOSAnalysis13/54分页举例假设进程需要读取0x20021406中的字节。分页单元将该地址划分为3个部分:0x20021406=00100000000000100001010000000110b页目录索引(0x80=128)页表索引(0x21)页内偏移(0x406)CR3+p1的页目录p1的页表+Present=0缺页异常XxxxxxXxxxxXxxxxxxx14关于虚拟内存的思考一关于虚
11、拟内存的思考一1.如何将同一块物理内存同时映射到多个进程的地址空间中?(共享内存是一种高效的进程间通信机制)2.如何将同一块物理内存同时映射到同一个进程地址空间的多个位置上?。3.多个进程同时装载同一个动态链接库时,该动态库在每个进程地址空间中的装载位置相同吗?4.如何做到将Linux内核代码和数据映射到每个进程的地址空间,并且随着进程切换只是改变用户地址空间的内容而内核地址空间内容保持不变?5.已知工作在用户态的应用程序不能访问内核空间的内存,那么如果一个应用程序申请了一块内存,如果将指向该内存的指针p传递给了一个内核态程序(例如某中断服务程序),那么内核态程序能通过指针p访问该内存吗?15
12、关于虚拟内存的思考二关于虚拟内存的思考二1.如果一个物理页中存储了某个进程的代码段,当该物理页因为内存紧张需要被重新分配给另外的进程时,需不需要将该物理页中的内容回写到磁盘交互文件中?2.如何将一个硬盘文件映射到一个进程地址空间的指定位置上?(内存映射函数mmap)3.对应ARM等不区分I/O地址空间和内存地址空间的CPU,如果已经知道了某外设寄存器的物理地址(通过该寄存器地址译码电路获得),如何在LinuxC程序中访问该寄存器?void*ioremap(unsignedlongphys_addr,unsignedlongsize)用于在页表中增加一个物理地址到虚拟地址映射。4.如何设置内存区
13、域为“只读”存储区?5.如何以当前进程为模板快速克隆出另外一个新的进程?(fork函数与CopyOnWrite技术)6.如何实现物理内存的“延迟分配”?16IPC机制:共享内存机制:共享内存1.intshmget(key_tkey,size_tsize,intflag);功能:得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符key:共享内存对象的全局标识,大于0的32位整数。通常要求此值来源于ftok返回的IPC键值。如果该内存被映射到同一进程地址空间,则令key取值为IPC_PRIVATE。size:共享内存区的字节数flag:读写的权限返回值:成功返回共享存储的id,失败返
14、回-117IPC机制:共享内存机制:共享内存1.void*shmat(intshmid,constvoid*addr,intflag);功能:连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问shmid:共享存储的idaddr:一般为0,表示连接到由内核选择的第一个可用地址上,否则,如果flag没有指定SHM_RND,则连接到addr所指定的地址上,如果flag为SHM_RND,则地址取整flag:SHM_RDONLY:为只读模式,其他为读写模式返回值:如果成功,返回共享存储段地址,出错返回-12.intshmdt(void*
15、addr);addr:共享存储段的地址,以前调用shmat时的返回值返回值18IPC机制:共享内存机制:共享内存1.intshmdt(void*addr);功能:与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存addr:共享存储段的地址,以前调用shmat时的返回值返回值:成功:0;出错:-119mmap内存映射内存映射1.利用mmap函数可以将一个磁盘文件或者其它设备对象映射到虚拟内存空间。文件被映射到多个页上,所有页的大小之和大于等于文件大小。20mmap内存映射内存映射1.void*mmap(void*start,size_tlength,intprot
16、,intflags,intfd,off_toffset)start:要映射到的虚拟内存区域的起始地址,通常都是用NULL,NULL表示由内核来指定该内存地址length:要映射的内存区域的大小prot:期望的内存保护标志,是以下的某个值,可以通过or运算符组合到一起1.PROT_EXEC可执行;2.PROT_READ可读;3.PROT_WRITE可执flags:指定映射对象的类型,映射选项和映射页是否可以共享。MAP_SHARED/MAP_PRIVATE/MAP_LOCKED/MAP_ANONYMOUSfd:文件描述符(由open函数返回)offset:表示被映射对象(即文件)从那里开始对映,通常都是用0。该值应该为大小应为PAGE_SIZE的整数倍返回值:成功则返回被映射虚拟内存区的指针,失败返回-1。21mmap内存映射内存映射1.intmunmap(void*start,size_tlength)取消映射关系2.intmsync(constvoid*start,size_tlength,intflags)将内存中的内容同步到文件思考:思考:mmap函数执行时会一次性将整个被映射文件读入内存吗?即用mmap函数映射一个大文件时会很耗时吗?谢谢你的阅读知识就是财富丰富你的人生