MMU和虚拟内存的问题7
发布网友
发布时间:2023-10-08 18:11
我来回答
共1个回答
热心网友
时间:2024-11-17 23:41
MMU就是干这个的,虚拟内存地址转译。
页面是MMU用来管理内存单元的,x86硬件体系下提供2种页面尺寸,4k和4M,而x64为4k和2M。大页面转译速度快,但缺点是往往把代码和数据放在同一页中,无法起到保护。
进程的4G内存空间是内核创建进程时候给予的,默认情况下2G属于内核空间,直接映射至内核,另外2G为用户空间,这点在32位系统中基本属于惯例,linux/unix某些版本可以支持8GB虚拟内存地址,而windows最多只能开启3GB,即内核压缩至1GB。
默认采用4GB内存地址的原因是32位外部总线最多只能寻址4GB内存,实际可以是任意大小,但会带来空间和速度上的损失,因而4GB对大多数情况而言是最佳选择。
进程创建时系统会为其提供一个页表,这个页表是一个2级数据结构(超过4G则需要3级,/PAE启动选项就会启用3级页表),其中512个页表是内核负责维护,进程无法改变他,进程可以使用的是独立的另512个。你应该已经知道,32位系统的内存寻址是直接使用32位数据的,对于进程而言,这32位的数据并非实际内存地址,其中10位用来表示页分组索引,每个进程都会维护这样一个分组索引;而另10位用来表示页索引,用来在分组中定位页面,最后12位则是相对地址,之所以是12位是因为windows采用了4k的页表,12位可以完全覆盖。
也就是说,内存被分为1024组,每组内1024个页,每页4k,总共4GB。开启PAE后情况稍稍有所变化,内存被分为2048组,每组内512个页,每页4k。系统维护512组,所以用户进程得以获得剩下的1536组共3GB。每个分组项是32位,4字节长,PAE下是8字节,每个页是4字节。所以总共是4M,你在这方面没理解错。不过进程只维护2M,另2M是内核维护的,进程只能去读取而不能修改它。他位于虚拟控件中属于内核的那2G。
整个4GB内存至此就完全分配完毕了,标准情况下,用户进程操作的只有2G,因此对于超过2GB内存的系统来说,进程无法使用全部内存,这也是pae和3gb的由来。
这么分配内存的根本原因是MMU,进程在运行中要用到实际物理页面时候他对此页面的实际地址是一无所知的,每个进程都拥有独立的2GB内存空间和所有进程共享的2GB内核空间,从而最大限度的保护进程内存,防止写其他进程的数据。这个2级的页表结构是MMU可读取的,PAE的第*则是软件的,因此PAE获得了最大128G的内存空间,但牺牲了硬件级的速度。
无论有没有虚拟内存,页表都必须存在,因为cpu会直接读取页表结构来确定内存地址。如果使用了虚拟内存,那么有可能操作一个页面时会发现页面不可用(无虚拟内存时这意味着out of memory,还有很多原因会导致页面错误,这些是系统内核的中断处理去负责),就会触发一个页面错误,这个页面错误属于硬件中断,操作系统提供一个中断处理函数,用来换页,页表的数据会自动被cpu读取,并换入物理内存,这也是为什么没有MMU的系统根本不可能实现虚拟内存的原因,换页是一个硬件中断,软件实现它的代价太过高昂。
关于ARM,没有读过文档,但他的MMU并非一个固定包含的模块,而是编号15的协处理器,你需要查看实际芯片制造商的data sheet来确定是否包含MMU,包含MMU的话(一般支持win ce就肯定有MMU,只有dos这种系统无需MMU),其处理模式应该类似于此,可能页表的格式,或页大小有些区别,但技术上来说是一样的。对于没有MMU的硬件,高级语言的动态内存分配几乎无法实现,因为进程的堆栈在初始化时就固定了,且不可更改。ucLinux利用一个系统维护的内存池实现了动态内存分配,因此一般采用ucLinux的硬件都不带MMU