操作系统——内存管理

内存管理

1.一段程序放入内存,cpu取指执行、取指执行,cup和内存都工作起来了

2.程序在内存中分段处理,因为每个段有不同的特点(代码段只读,数据段可写,堆栈段单向增长),分治

3.在内存中找一段空闲内存,将一段(代码段、数据段)程序放入内存

4.取指执行,跳转到某个地址,需要运行时重定位,记录基址,ldtr寄存器就是放到段表ldt表。根据基址和偏移地址算出真正的物理地址。

5.每个进程有自己的ldt,都放入pcb中的

6.多进程切换,修改ldtr。(多进程的那个映射表就是ldt)

总结:

1)程序分段:编译做的事情

2)在内存中找到空闲区域(算法数据结构)

3)通过磁盘读写将程序载入内存,建立映射表和PCB关联在一起

怎么在内存中找到空闲区域,内存怎么分割?

内存等分成k个分区?可变分区?——虚拟内存分区,物理内存分页

如何管理可变分区?(空闲分区表:始址和长度,已分配分区表:始址、长度和标志)

算法:一个问题多个解,看哪个解更合适(没有错误的算法,只有更合适的算法,折中综合)

首先适配、最佳适配、最差适配

为什么分页

分页

分区导致的问题,可能内存剩余210k(150+60),但是有个160k大小的内存,就放不进去了,这就是内存碎片。

移动碎片的过程叫内存紧缩,内存紧缩的时候上层应用无法执行,看起来像死机。

面包没有碎末,面包切成片,内存分成页,针对每个段请求,系统一页一页的分配给这个段,一个段最多浪费一页(4k)

物理内存关心内存没有浪费,用分页;用户希望分段。段页合在一起。

某个偏移地址被放在哪里了。用到页表,同样地址重定位,cr3页表

mmu:内存管理单元,逻辑地址算出页号,对应的页框,然后找到实际的物理地址

多级页表和快表

页小了,页表就大了,

32位的计算机,内存4G

如果每页4k,那么页表项有1M个,页表很大,页表的放置会出问题,

每个页表项一般4个字节,也就是4M

如果操作系统中有上百个进程,每个进程都要存放这样的一个页表,那就是400M

实际上大部分逻辑地址是用不到的,

如果仅仅存放使用到的逻辑页,那么检索是个问题,时间复杂度太高

我们的目标:既要连续又要页表占用内存少,引出了多级页表(页目录表和页表),把容量为1M个页表项的页表变为1个页目录表(里面1k个页目录)和1k个页表(每个页表有1k个页表项),这样全填充的话是4G空间全部用上,但是可以只选用其中一部分,这样就大大节省了空间同时保证了地址空间的连续。

但是每增加一级页表,要多访问一次内存,若64位操作系统,那么访问内存次数还是挺多的。时间上造成的代价用快表TLB来弥补,放在寄存器中,速度和cpu一样快,快表很昂贵,采用复杂的硬件电路根据页号直接找到,只需一次比对。若查到了,则不用再去查多级页表,查完后就把查询的结果放在快表中。

操作系统折中的思想,多种技术有机的组合在一起,时间上也不错,空间上也不错,效率也比较高。多级页表提高了空间利用效率,时间上的不足由快表来弥补。

想让TLB好用,命中率要接近1,越大越好,但是TLB比较贵,所以要折中,最终TLB条目设置为64-1024之间,因为程序的地址访问存在局部性。

总结:多级页表、快表加程序地址访问的局部性

一个实际的段、页结合的内存管理

两层映射:逻辑地址到虚拟地址,虚拟地址到物理地址

面向用户采用段的结构,面向物理内存采用页的结构,灵魂在虚拟内存

分配虚拟内存(段)、建段表;分配页、建页表 ——>进程带着内存使用起来

从进程fork中的内存分配开始,使用内存结束

程序分段,利用分区算法把程序段或者数据段放在虚拟内存上,虚拟内存中分出来的区打散成几个页放在物理内存中

简化后的进程之间虚拟地址不重叠,那么页表和段表也不重叠,所以大家可以共用一套页表,实际的操作系统页号很可能重叠的,所以每个进程有自己的页号和段号

后面的代码看不懂了。。。。。。。

内存的换入

内存管理:基于虚拟内存实现的分段和分页,而用换入换出来实现这个虚拟内存

为了实现虚拟内存就要实现换入换出

操作系统看不到实际的内存,它看到的是0-4G的地址空间,操作系统给用户提供的假象,就是一整段内存,随意使用,操作系统内部实现了分页和映射。

虚拟内存4G,实际物理内存1G,怎么做?换入换出!

请求的时候才映射!请求调页

访问内存的时候如果MMU发现缺页了,则中断,从仓库中调出这一页,放入内存,中断结束,回来后代码继续执行(这里不从下一行代码开始,而是从本行代码开始)

操作系统程序从缺页中断开始(14号中断),在内存中申请一个空闲页,从磁盘上把这一页读进来,建立一个映射

内存换出 swap out

在get_free_page()的时候,并不能总是得到新的页,内存是有限的,选择哪一页淘汰呢?这个算法放在get_free_page()中

算法优化目标:缺页次数少

FIFO:如果刚换出的页马上又要换入怎么办?

要用一个页了,没空间了,换出哪个页?不向前看向后看,哪个使用时间距离现在最远就换哪个,这就是MIN算法,但是这个算法需要知道将来要发生的事情。

现实世界数据的特点:稀疏性、局部性、低质性

LRU:因为程序的局部性,所以可以用过去的历史预测未来。选择最近最少使用的页来进行换出。LRU是公认的很好的置换算法,但实际系统中准确实现用的少。

LRU的准确实现,每页维护一个时间戳(time stamp),选具有最小时间戳的页。

想着挺好,实际使用中,每执行一条访问地址的指令要查表,修改时间戳,需要维护一个全局时钟,还要预防时间戳的表溢出。。。实现代价太大

LRU近似实现——将时间计数器变为是和否

每个页加一个引用位(reference bit),没次访问一页时,硬件自动设置该位。选择淘汰页:扫描该位,是1时清零,并继续扫描,是0时淘汰该页,这叫二次机会算法。

二次机会算法记录了太长的历史,如果缺页很少的时候,退化成了FIFO算法

Clock算法:在二次机会算法的基础上加一个定时清除R位的扫描指针。

给进程分配多少页框(帧frame),求出工作集,就算出一个进程应爱分配多少个页框。

进程数量太大,导致cpu利用率下降,可以限制进程的数量。

swap分区管理 —> 虚拟内存 —> 段页 —> 程序 —> 进程

初始化、系统接口,加上设备驱动,整个计算机运行的样子就出来了。

你可能感兴趣的:(操作系统——内存管理)