页框, 页帧:传统上,把内存视为连续的字节,即内存为字节数组,内存单元的编号(地址)可作为字节数组的索引。分页管理时,将若干字节视为一页,比如4K bytes 此时,内存变成了连续的页,即内存为页数组,每一页物理内存叫页帧,以页为单位对内存进行编号,该编号可作为页数组的索引,又称为页帧号。页帧和页框是一个东西,英文page frame。页帧号表示物理内存的第几页, 页框表示实实在在的物理内存页。
内碎片, 外碎片:在内存管理中,内部碎片是已经被分配出去的的内存空间;外部碎片是指还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。固定分区存在内部碎片,可变式分区分配会存在外部碎片;页式虚拟存储系统存在内部碎片;段式虚拟存储系统,存在外部碎片。外部碎片:因为行程持续地被载入与置换,使得可用的记忆体空间被分割成许多不连续的区块。虽然记忆体所剩空间总和足够让新行程执行,却因为空间不连续,导致程式无法载入执行。内部碎片:发生在以固定长度分割区来进行配置的记忆体中当一个程式载入到固定大小的分割区时,假如程式小于分割区,则剩余的空间将无法被使用,称为内部碎片。利用聚集或分页可以消除外部碎片。这页说明了分页机制为什么可以消除外碎片,而为什么有内碎片。因为系统分页都是以4KB的页为单位进行分配的。
假设内存是连续分配的(也就是程序在物理内存上是连续的)
1.进程A进来,向os申请了200的内存空间,于是os把0~199分配给A
2.进程B进来,向os申请了5的内存空间,os把200~204分配给它
3.进程C进来,向os申请了100的内存空间,os把205~304分配给它
4.这个时候进程B运行完了,把200~204还给os
但是很长时间以后,只要系统中的出现的进程的大小>5的话,200~204这段空间都不会被分配出去(只要A和C不退出)。
过了一段更长的时间,内存中就会出现许许多多200~204这样不能被利用的碎片……
而分页机制让程序可以在逻辑上连续、物理上离散。也就是说在一段连续的物理内存上,可能0~4(这个值取决于页面的大小)属于A,而5~9属于B,10~14属于C,从而保证任何一个“内存片段”都可以被分配出去。
先介绍一下三个地址:物理地址、逻辑地址、线性地址,物理地址:存储的是硬件系统中真实存在的物理内存空间,是实物,看得见摸得着的东西。物理内存的访问通过硬件系统总线进行的,一般的32位的机器上都具有4GB的物理地址空间。注意,是一般状况。逻辑地址:X86体系结构CPU中,有若干个段寄存器,“段寄存器+偏移地址”即可表示内存地址。使用这种方式表示的地址称为“逻辑地址“,系统会自动个将逻辑地址转换为线性地址。就本人理解,所谓的逻辑地址只是相关人员为了方便自己理解,所使用的一种机制,用的是人们的正常理解方式。在汇编里面经常见到”段地址+偏移地址“的概念。线性地址:与物理地址类似,是没有分段的概念的,地址是连续的。逻辑地址和线性地址都要映射成物理地址,之所以又多出一个线性地址,而不是直接用一个逻辑地址就来代替来的原因是,在386架构中,cpu可以出于是模式和保护模式两种模式下,在实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制,cpu不进行自动地址转换)而在保护模式下必须先将逻辑地址转化为线性地址,在看是或否采用了分页机制,若果没有分页,那么此线性地址等于物理地址,若采用了分页机制,则再通过地址转换(相关的经过分页目录、分页表的具体映射过程读者可以上网参阅资料)映射成物理地址。内存管理正式使用了分页机制,才使得不同进程之间的地址能够和平相处,即不同进程指向的线性地址可以相同,然后经过分页机制,转化成不同的物理地址,这就是分页的好处。然而当物理内存不够了又该怎么办了?分页机制提出了一种很有创意的想法,就是虚拟地址!通过分页机制将原本指向物理内存的地址映射到硬盘中,充分发挥硬盘存储容量大的优点,合理利用资源,可以说是分页机制的完结啊!
什么是虚拟存储:
虚拟存储器的思想是程序、数据和堆栈的大小都有可能超过物理内存大小,由操作系统把当前使用的放在内存,而不需要的放在磁盘。而绝大部分操作系统使用的虚拟存储器技术就是分页技术。 在虚拟存储器中,程序所产生的地址为虚拟地址,虚拟地址构成了虚拟地址空间。(当然了在没有虚拟存储器的系统上,程序产生的地址就是物理地址。其实程序并不知道,只是操作系统和处理器知道。下面都是按照使用虚拟存储器的系统来说)这些虚拟地址通过MMU(内存管理单元)映射为物理地址,采用分页机制的系统,虚拟地址空间以页面为单位进行划分,虚拟地址空间会被划分成多个等大小的页面。物理地址空间也按页面为单位进行划分每一块成为页帧,或者页框。每一虚拟页面可以随意对应到物理页框,也可以对应到磁盘的页面文件的上。分页式管理可以给每个应用程序虚拟的分配4G的内存空间;程序运行时物理内存不足时可以将不常用的内存页交换到硬盘上,当需要交换到硬盘上的页时,会触发处理器的中断将硬盘上的页读到内存里。
buddy算法是用来做内存管理的经典算法,目的是为了解决内存的外碎片。
避免外碎片的方法有两种
1,利用分页单元把一组非连续的空闲页框映射到非连续的线性地址区间。
2. 开发适当的技术来记录现存的空闲连续页框块的情况,以尽量避免为满足对小块的请求而把大块的空闲块进行分割。
内核选择第二种避免方法
基于下面三种原因,内核选择第二种避免方法:1,在某些情况下,连续的页框确实必要。2,即使连续页框的分配不是很必要,它在保持内核页表不变方面所起的作用也是不容忽视的。假如修改页表,则导致平均访存次数增加,从而频繁刷新TLB。3,通过4M的页可以访问大块连续的物理内存,相对于4K页的使用,TLB未命中率降低,加快平均访存速度。
buddy算法将所有空闲页框分组为10个块链表,每个块链表的每个块元素分别包含1,2,4,8,16,32,64,128,256,512个连续的页框,每个块的第一个页框的物理地址是该块大小的整数倍。如,大小为16个页框的块,其起始地址是16*2^12(一个页框的大小为4k,16个页框的大小为16*4K,1k=1024=2的10次方,4k=2的12次方)的倍数。 例,假设要请求一个128个页框的块,算法先检查128个页框的链表是否有空闲块,如果没有则查256个页框的链表,有则将256个页框的块分裂两份,一份使用,一份插入128个页框的链表。如果还没有,就查512个页框的链表,有的话就分裂为128,128,256,一个128使用,剩余两个插入对应链表。如果在512还没查到,则返回出错信号。
回收过程相反,内核试图把大小为b的空闲伙伴合并为一个大小为2b的单独快,满足以下条件的两个块称为伙伴:1,两个块具有相同的大小,记做b;2,它们的物理地址是连续的,3,第一个块的第一个页框的物理地址是2*b*2^12的倍数,该算法迭代,如果成功合并所释放的块,会试图合并2b的块来形成更大的块。