OS之《内存管理》

程序装入方式

  1. 绝对装入:程序逻辑地址和物理地址是完全对应的。不现实
  2. 可重定位装入:装入的时候重新 计算内存地址。程序中的实际地址加上程序载入的起始地址;但是解决不了进程挂起 后重新唤醒的问题。唤醒的后的进程载入内存地址,位置一定会发生改变的。
  3. 动态运行时载入:专门有一个重定位寄存器,记录进程中程序和数据的内存起始地址;这样程序中的逻辑地址到 运行的时候加上重定位寄存器的数值,就是实际内存的逻辑地址;

程序连接方式

  1. 静态连接:将编译后的多个模块,一次性连接在一起,形成一个完整的文件。此时,连接后的程序在这个完成的文件里面就有了新的地址。完成的文件就不再拆开了。

  2. 装入时动态链接:编译后的一组模块,采用边载入边链接的方式。就是载入目标模块发生外部模块调用,就会将外部模块装入内存。
    2.1 在发生某一个模块修改或者更新的时候, 更新个别的模块就可以了。
    2.2 便于实现对目标模块的共享:如果是静态连接的方式,每一个完整的模块都将包含目标模块的拷贝。无法实现共享;动态连接就可以共享;

  3. 运行时动态链接:代码运行的时候需要某些模块不在内存中,就动态的加入内存,然后将其链接到调用这模块上。
    3.1 凡是在运行过程中没有被用到的模块,就都不会被调入内存和被链接到调用者程序。这样加快了程序的载入过程,而且节省了空间。
    3.2 一个程序可能很大,但是当前执行起来并不需要所有的模块都加载进来。全部加载进来一个是慢,一个是浪费内容空间。

内存分配方式

  1. 单一连续分配:适合单道程序;内存分用户区和系统区;这样独占了用户去内存区域了;简单,没有碎片;
  2. 固定分区:分区大小固定,可以分配多个分区,每一个进程独占一个分区;
    2.1 分区大小相等:程序大,装不下;程序小,浪费;
    2.2 大小不等:根据程序的大小,分配不同大小的内存空间

内存分配

对分区按照其大小进行排队,建立一张分区表;包括分区号,分区大小,起始地址,是否分配等信息;
当有程序载入时,有内存分配程序依据用户程序的大小在表中检索,从中找到能满足程序大小的,并且是没有分配的分区,分配给该程序,然后将内存表中的该分区标记为已分配。

动态分区分配

动态分区分配又称为可变分区分配,是指根据进程的实际需要,动态的为之分配内存空间。分区分配中所用的数据结构、分区分配算法、分区的分配和回收这三方面的问题。

动态分区的数据结构

1.空闲分区表
2.空闲分区链:除了存基本信息,链表中的节点可以存更多的信息

分配内存

从链表中查找合适位置,修改是否分配状态(大小正好合适),或者修改链表(有剩余,需要分裂),然后将该分区的首地址返回。

回收内存

内存使用完成后,还要回收。这时会出现以下可能。该节点前后分区是否空闲,如果遇到空闲,则需要合并。

基于顺序搜索的动态分区分配算法

四种算法如下:
1.首次是适应算法:每次从前往后找,只要找到一个合适的就停止
2.循环首次适应算法:每次不是从头开始,而是从上次位置找到的位置开始向后找,如果找到尾部还没有找到,就从头开始找到上次位置。
3.最佳适应算法:要求空闲表要从小到大,第一个找到的就是既能满足大小的,碎片又小。这样系统就留下了很多不可用的小的碎片;
4.最坏适应算法:每次都要找一个最大的分区来使用,从大的中间分割出一部分。要求从大到小,找第一个即可。

基于索引搜索动态分区分配算法

1.快速适应算法:更具每一个分区大小,将分区分成多区表;大小相同的分区链接在一起,组成一个分区表。

a.若,需要找到一个程序应该给它分配哪一个分区,应该先据大小,锁定是在哪个分区表中查找。这样更高效。缺点是归换内存时麻烦。
b.一个程序占用大小和分区大小不相同,就会出现内存浪费的情况;

2.hash算法:将大小相同的闲分区,放在同一个链表中;再将这些列表用has表包一层。当程序需要指定大小的分区时,直接通过has能定位到是在哪个链表中,找到该链表的第一个空闲分区句可以了

动态可重定位分区分配

1.紧凑型:连续分配方式,要求程序必须载入到一个连续的内存空间。当计算机运行一段时间有,必然会被分割成很多个小空间。当,多个空间不能连续的时候,对于一个大的程序就无法被满足,实际上不连续的加起来空间是以满足该程序的。碎片话的内存就需要重新整理,将碎片内存在一起,被使用不连续的也移动到一起。频繁发生移动,严重影响性能。不考虑。
2.动态重新位:进程中程序执行的时候,才会将具体的指令逻辑地址转换成物理地址,为了保证这一转换效率高,基本不消耗性能。这里需要用到重定位寄存器。它记录了进程使用的基地址。因为程序中逻辑地址是冲0始的,所以执行的时候加上基地址就真实的逻辑地址。 当系统对内存进程碎片化整理时,只需要修改进程中的重定位地址寄存器上的值就可以。不影响程序运行。

Swapping技术

交换技术主要解决内存不够用的问题。当一个就绪态进程被选中到cpu执行时,发现系统内存不够用的时候,需要将有些进程挂起,也称为中级调度。临时到外存上。等到下次执行的时候,再从外存调回内存使用。
交换类型:
1.整体交换:是指将一个进程,整个的放到外存。优点,简单。
2.分段交换:是指可以将一个进程中的某一段占用的内存数据,换到外寸上去。因为一个程序对于那些执行完了的,或者还没有内使用的内存段,可以交换到外寸上。

实现swapping技术,必须实现的功能

1.交换空间管理:那些被交换到外存的进程要怎么样存储在哪些地方。
2.进程换出:

a.找到要换存的进程:首先选择处于阻塞或者睡眠的进程,其次是按照优先级;如果优先级都是一样的,那就按照在内存中驻留的时间
b.换出过程:只能换出那些不共享的程序或者数据。以为采用分模块运行时动态连接的方式,所以一个模块可能被多个进程使用呢。现在外存申请存储空间,申请成功才会启动磁盘,将数据写入,然后对PCB数据结构进行修改。

3.进程换入:从就绪列表中找到进程载入列表。如果缺页减率减少,系统吞吐量下降时,暂停运行对换程序。

分页存储管理方式

1.分页存储:页号|位偏移量,页表中和物理内存的块号做映射,还有一个标记当前页号对应的空间是否已被分配出去。

a.每个进程在最后一页都可能产生 ,页内碎片

2.分段存储

a.信息共享。每一个模块的程序可以被多个进程引用,减少存储
b.信息保护。一个段就可以控制了
c.动态增长。只修改一个模块对应的一个段的大小即可
d.动态链接。程序用到的时候才加载进来。

3.段页存储:外层段表,内存页表

地址转换

  • 对于一个给定的虚拟地址,首先将其分为两部分:页号和页内偏移。假设虚拟地址为 32 位,页面大小为 4KB,那么高 20 位表示页号,低 12 位表示页内偏移。
  • 以虚拟地址0x12345678为例,根据页面大小,将其划分为页号0x1234和页内偏移0x5678。
  • 然后,通过页号查找页表,找到对应的物理页面号。如果页表项中存在有效的物理页面号映射,就获取该物理页面号。
  • 最后,将获取的物理页面号与页内偏移组合起来,就得到了对应的物理内存地址。例如,如果找到的物理页面号为0xABCD,那么物理内存地址就是0xABCD5678。

不论是哪种表,都要两次访问内存,低效。所以,有了快表(特殊的高速缓冲区),还有对应物理硬件支持,使用高速缓存寄存器。
但是,这种缓冲大小有限,所以如何高效的利用,才是关键。
有效访问时间是衡量的重要指标。在没有引用高速缓冲器的时候,需要两次访存的时间为2t。在使用以后,随着命中率的提高,有效访问时间有明显提升。
如何提高命中率,是一个有趣的领域。
硬件中,局部性原理,指令和数据在主存中都是连续存放的。所以,程序一段时间内基本上都是连续使用同样的数据。
由于高速缓冲大小有限,所以,页表和段表一般需要用多级才能实现。

posted @   Eular  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示