操作系统面试——存储管理等

本文深入探讨了操作系统中的存储管理,包括逻辑地址与物理地址的关系、虚拟内存的工作原理、页面调度的几种方式(页式、段式、段页式)以及它们的优缺点。此外,还介绍了内部碎片与外部碎片的区别,以及页面置换算法如最佳置换、先进先出和最近最久未使用等。最后,文章提到了动态链接库与静态链接库的差异和作用,以及中断、异常和系统调用的概念和它们在程序执行中的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

逻辑地址与物理地址

https://zhuanlan.zhihu.com/p/90004914
https://zhidao.baidu.com/question/758288636125599364.html
在这里插入图片描述

  1. 逻辑地址(Logical Address)
    (1)是指由程序产生的与段相关的偏移地址部分
    (2)例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址,不和绝对物理地址相干。
  2. 物理地址(Physical Address)
    (1)是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。
    (2)如果启用了分页机制,那么线性地址会使用页目录和页表中的变换成物理地址。
    (3)如果没有启用分页机制,那么线性地址就直接成为物理地址了。

线性地址(Linear Address):是逻辑地址到物理地址变换之间的中间层
在分段部件中逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。

虚拟内存

https://baike.baidu.com/item/虚拟内存/101812?fr=aladdin

虚拟内存(Virtual Memory):计算机呈现出要比实际拥有的内存大得多的内存量。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

每个进程创建加载的时候,会被分配一个大小为4G的连续的虚拟地址空间,虚拟的意思就是,其实这个地址空间时不存在的,仅仅是每个进程“认为”自己拥有4G的内存,而实际上,它用了多少空间,操作系统就在磁盘上划出多少空间给它,等到进程真正运行的时候,需要某些数据并且数据不在物理内存中,才会触发缺页异常,进行数据拷贝。

调度方式

  1. 页式调度
    (1)虚拟空间被分成大小相等的页,称为逻辑页或虚页。主存空间也被分成同样大小的页,称为物理页或实页。
    (2)通过页表可以把虚拟地址转换成物理地址。每个程序设置一张页表,对应每一个虚页号都有一个条目,包含该虚页所在的主存页面地址(实页号),与虚拟地址的页内地址相拼接,就产生完整的实存地址
    (3)优点是页长固定,便于构造页表、易于管理,且不存在外部碎片
    (4)缺点是页长与程序的逻辑大小不相关。例如,某个时刻一个子程序可能有一部分在主存中,另一部分则在辅存中。不利于编程时的独立性,并给换入/换出处理、存储保护和存储共享等操作造成麻烦。
  2. 段式调度
    (1)按照程序的划分的、长度可以动态改变的区域。
    (2)通常,程序员把子程序、操作数和常数等不同类型的数据划分到不同的段中,可以有多个相同类型的段。
    (3)虚拟地址由段号和段内地址组成。
    (4)虚拟地址到实存地址的变换通过段表来实现。每个程序设置一个段表,段表的每一个表项对应一个段,每个表项至少包括三个字段:有效位有效位(指明该段是否已经调入主存)、段起址(该段在实存中的首地址)和段长(记录该段的实际长度)。
  3. 段页式调度
    (1)段式虚拟存储器和页式虚拟存储器的结合。
    (2)首先,实存被等分成页。把程序按逻辑结构分段以后,再把每段按照实存的页的大小分页,程序按页进行调入和调出操作。
    (3)优点是既拥有分段系统的共享保护,又拥有分页系统的虚拟内存功能。
    (4)缺点是在地址映像过程中需要多次查表,虚拟地址转换成物理地址是通过一个段表和一组页表来进行定位的。

分段和分页

https://blog.youkuaiyun.com/qq_37924084/article/details/78360003
https://www.jianshu.com/p/a805e2410fbe

产生背景:连续分配内存方式会形成许多“碎片”,虽然可通过“紧凑”方法将许多碎片拼接成可用的大块空间,但须为之付出很大的开销,如果允许将一个进程直接分散地装入到许多不相连的分区中,便可充分地利用内存空间

  1. 分段机制
    (1)把用户程序的地址空间分为若干个大小不同的段。
    (2)段的第一个字节在线性地址空间中的位置(称为段的基地址)。
  2. 分页机制
    (1)将用户程序地址空间分为若干固定大小的区域。
    (2)分页机制建立在分段机制的基础上,因此分页是在分段之后进行的。
    (3)为什么要分页:内存一旦被分割成碎片就无法载入较大进程;以段为单位的交换太大费时间。
  3. 比较:
    (1)段是信息的逻辑单位,含有一组其意义相对完整的信息,是根据用户的需要划分的,因此段对用户是可见的;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明(不可见,用户无需关心)的。
    (2)段大小不固定,由它所完成的功能决定;页大小固定,由系统决定。
    (3)分段的地址空间是二维的,段名和段内地址;分页的地址空间是一维的,因为分页的大小固定,且页码连续。
    (4)分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护;分页主要用于实现虚拟内存,从而获得更大的地址空间。
    (5)段表存储在线性地址空间,而页表则保存在物理地址空间。

内部碎片与外部碎片

https://baike.baidu.com/item/内存碎片/3883950?fr=aladdin

  1. 内部碎片
    (1)是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间,处于区域内部或页面内部
    (2)内存分页后的最后一页往往装不满,于是形成了内部碎片。
  2. 外部碎片
    (1)是还没有被分配出去(不属于任何进程),但由于太小了无法分配给新进程的内存空闲区域,处于已分配区域或页面外部
    (2)这些存储块的总和可以满足当前申请的长度要求,但是由于地址不连续或其他原因,使得系统无法满足当前申请。

页面置换算法

https://baike.baidu.com/item/页面置换算法/7626091?fr=aladdin
https://www.jianshu.com/p/18285ecffbfb

  1. 最佳置换算法(OPT)
    (1)每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,可以保证最低的缺页率。
    (2)一种理想情况下的算法,但是操作系统无法提前预判页面的访问序列,所以实际上不可能实现
    (3)可以用于对可实现算法的性能进行衡量比较。
  2. 先进先出置换算法(FIFO)
    (1)每次选择淘汰的页面是最早进入内存的页面。
    (2)只有FIFO算法会产生贝莱迪异常
    (3)与进程实际运行时的规律不适应,因为先进入的页面也可能最经常被访问,算法性能差
  3. 最近最久未使用算法(LRU)
    (1)每次淘汰的页面是最近最久未使用的页面。
    (2)确定最后使用时间的顺序方法有:计数器或逻辑时钟(每次访问就加1)、(每次访问就置顶)。
    (3)效果好,但需要硬件的支持和一定的软件开销,所以实际实现的都是一种简单有效的近似算法NRU。
  4. 最近未使用算法(NRU)
    (1)在存储分块表的每一表项中增加一个引用位,操作系统定期将其置为0
    (2)当某一页被访问时,由硬件将该位置1。
    (3)过一段时间后,检查这些位,把是0的页淘汰出去,因为在之前最近一段时间里它未被访问过。
    (4)就是时钟置换算法(Clock),是一种性能和开销均平衡的算法。
  5. 最不常用算法(LFU)
    (1)缺页时,置换访问次数最少的页面。
    (2)在内存中的每个页面设置一个移位寄存器,用来记录该页面被访问的频率。
    (3)存储器访问速度高,在1 ms时间内可能对某页面连续访问成千上万次,因此,通常不能直接利用计数器来记录某页被访问的次数,而是采用移位寄存器方式。
    (4)每次访问某页时,便将该移位寄存器的最高位置1,再每隔一定时间右移一次,因此并不能真正反映出页面的使用情况。

贝莱迪(Belay)异常:为进程分配的物理块数增大时,缺页次数不减反增的异常现象。

动态链接库与静态链接库

https://blog.youkuaiyun.com/li1914309758/article/details/82145023

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
库有两种:静态库(.a、.lib)和动态库(.so、.dll)。
windows上对应的是.lib .dll linux上对应的是.a .so

  1. 静态链接库:在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。
    (1)静态库对函数库的链接是放在编译时期完成的。
    (2)程序在运行时与函数库再无瓜葛,移植方便
    (3)代码装载速度快,执行速度略比动态链接库快;
    (4)浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件,包含相同的公共代码,导致可执行文件体积较大。
    (5)另一个问题是静态库对程序的更新、部署和发布会带来麻烦。如果某个静态库更新了,所有使用它的应用程序都需要重新编译、发布给用户。
  2. 动态链接库:动态库在程序编译时并不会被连接到目标代码中。
    (1)动态库是在运行时期载入的。
    (2)使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败。
    (3)速度比静态链接慢
    (4)不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题,可以实现进程之间的资源共享(因此动态库也称为共享库)。
    (5)动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦,用户只需要更新动态库即可,增量更新

其他

中断、异常、系统调用

https://blog.youkuaiyun.com/rainlight/article/details/636089
https://blog.youkuaiyun.com/zy704599894/article/details/81184577
https://blog.youkuaiyun.com/weixin_44302602/article/details/110352857

中断(广义)

中断:在系统中发生某一紧急事件时,也可以要求处理机暂停当前正在执行的程序,转去执行该事件的处理程序。待事件处理结束后,再回到被中断程序的中断点继续执行。

由于操作系统的管理工作需要特权指令,因此CPU要从用户态转换成核心态。
用户态转化到核心态是通过中断实现的,并且中断是唯一途径。
核心态转化到用户态是通过执行一个特权指令,将程序状态字的标志位设置为“用户态”。

  1. 分类:
    (1)内中断(内部异常):
    陷阱(同步):有意而为之的异常(系统调用);
    故障(同步):潜在可恢复的错误;
    终止(同步):不可恢复的错误,如程序故障(非法操作码、地址越界、浮点溢出等)。
    (2)外中断
    中断(异步):I/O中断、时钟中断、控制台中断等;
    ② 人工干预。
  2. 中断处理:一般分为中断响应和中断处理两个步骤。中断响应由硬件实施,中断处理主要由软件实施。
    (1)在每次执行完每个指令后,CPU都要检查当前是否有外部中断信号
    (2)如果检测到外部中断信号,则需要保护被中断进程的CPU环境
    (3)根据中断信号类型转入相应的中断处理程序
    (4)恢复原进程的CPU环境并退出中断,返回原进程继续往下执行。

中断(狭义)

来自硬件设备的处理请求。

  1. 处理机制:持续,对用户应用程序是透明的。
  2. 响应方式:异步

异常

非法指令或者其他原因导致当前指令执行失败(如:内存出错)后的处理请求。

  1. 处理机制:杀死或者重新执行意想不到的应用程序指令。
  2. 响应方式:同步

系统调用

应用程序主动向操作系统发出的服务请求。

  1. 处理机制:等待和持续。
  2. 响应方式:异步或同步
  3. 分类:
    (1)设备管理
    (2)文件管理
    (3)进程控制
    (4)进程通信
    (5)内存管理

一个程序从开始运行到结束的完整过程

https://www.nowcoder.com/discuss/611763

  1. 预处理:主要处理源代码中的预处理指令,引入头文件,去除注释,处理所有的条件编译指令,宏替换,添加行号。生成.i文件;
    $gcc -E hello.c -o hello.i
  2. 编译:编译过程所进行的是对预处理后的文件进行语法分析、词法分析、符号汇总,然后生成汇编代码。生成.s文件;
    $gcc -S hello.i -o hello.s
  3. 汇编:将汇编文件转换成二进制文件,即转变成机器可以执行的指令。生成.o文件;
    $gcc -c hello.s -o hello.o
  4. 链接:把生成的所有的目标文件组装到一起的过程,把它们相互引用的部分处理好,正确衔接成一个可执行文件。生成.out文件。

缓冲区溢出及其危害

https://baike.baidu.com/item/缓冲区溢出/678453?fr=aladdin

缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。

  1. 原因: 主要原因是程序中没有仔细检查用户输入。
  2. 危害:
    (1)程序崩溃,导致拒绝服务。
    (2)跳转并且执行一段恶意代码。
  3. 利用缓冲区溢出攻击:
    (1)原理:通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。
    (2)后果:导致程序运行失败、系统宕机、重新启动等;更严重的是,可以利用它执行非授权指令,甚至取得系统特权,进行各种非法操作。
    (3)防范方法:
    ① 完整性检查:在程序指针失效前进行完整性检查。
    ② 非执行的缓冲区:通过使被攻击程序的数据段地址空间不可执行,从而使得攻击者不可能执行被植入被攻击程序输入缓冲区的代码。
    ③ 关闭端口或服务,设置防火墙,及时更新补丁等。

系统调用与库函数

https://zhuanlan.zhihu.com/p/117626599

  1. 系统调用(system call)
    (1)是操作系统内核提供的函数,在内核态(kernel mode)运行,是操作系统为用户提供的一些接口。
    (2)它通过软中断向内核态发出一个明确的请求。有一些任务需要进程跑在内核态才能执行,比如和硬件打交道。所以进程调用系统调用就能让自己运行在内核态从而执行这些类似的任务。
    (3)意义是提高系统安全性。系统调用是内核代码,内核代码能访问系统上的所有地址空间,而我们执行的代码是用户空间的代码,用户空间的代码在对系统进行操作时是有限制的。
  2. 库函数
    (1)是高层的,是在系统调用上的一层包装,运行在用户态(user mode),为程序员提供调用真正的在幕后完成实际事务的系统调用的更为方便的接口。
    (2)可分为两类:没有调用系统调用(比如strlen),以及调用了系统调用(比如malloc使用brk或者sbrk系统调用来实现内部分配,比如printf调用write系统调用)。
  3. 系统调用和库函数的区别:
    (1)只有系统调用有权限访问硬件
    (2)系统调用通常不可替换;库函数通常可替换(改成自定义的)。
    (3)系统调用运行在内核空间;库函数运行在用户空间
    (4)系统调用调试很麻烦,因为运行在内核;库函数很方便。
    (5)系统调用是为了方便应用程序使用操作系统的接口;库函数是为了方便人们编写应用程序而引出的。
    在这里插入图片描述

IO多路复用

https://www.jianshu.com/p/397449cadc9a
https://zhuanlan.zhihu.com/p/115220699
https://www.zhihu.com/question/32163005/answer/1644076216

单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力。
解决的本质问题是在用更少的资源完成更多的事。

IO多路复用的三种机制Select,Poll,Epoll(都是系统调用):

  1. Select
    (1)把想监控的文件描述符集合通过参数的形式传递给select,然后select将它们拷贝到内核中。
    (2)为了减少数据拷贝带来的性能损耗,Linux内核对集合的大小做了限制,规定用户监控的文件描述集合不能超过1024个。
    (3)select返回后仅能知道有些文件描述符可以读写了,但不知道是哪一个,因此程序员必须再遍历一边找到具体是哪个文件描述符可以读写,效率低下。
    (4)将监听的文件描述符分为三组,每一组监听不同的需要进行的IO操作。readfds是需要进行读操作的文件描述符,writefds是需要进行写操作的文件描述符,exceptfds是需要进行异常事件处理的文件描述符。这三个参数可以用NULL来表示对应的事件不需要监听。
  2. Poll
    (1)和select非常相似,poll相对于select的优化仅仅在于解决了文件描述符不能超过1024个的限制
    (2)select和poll都会随着监控的文件描述增加而出现性能下降,因此不适合高并发场景。
    (3)和select用三组文件描述符不同的是,poll只有一个pollfd数组,数组中的每个元素都表示一个需要监听IO操作事件的文件描述符。
  3. Epoll
    (1)实际上文件描述符集合变化的频率比较低,对比select和poll频繁的拷贝整个集合,epoll通过引入epoll_ctl只操作有变化的文件描述符。
    (2)epoll和内核共享一块内存,这块内存中保存的是已经可读或者可写的的文件描述符集合,减少了内核和程序的内存拷贝开销
    (3)获取事件的时候,无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。
    (4)epoll是Linux目前大规模网络并发程序开发的首选模型。在绝大多数情况下性能远超select和poll
    在这里插入图片描述

相关缩写

OPT(Optimal,最佳置换算法)
FIFO(First-In First-Out,先进先出置换算法)
LRU(Least Recently Used,最近最久未使用算法)
LFU(Least Frequently Used,最不常用算法)
NRU(Not Recently Used,最近未使用算法)
DLL(Dynamic Link Library,动态链接库)
FD(file descriptor,文件描述符)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值