目录

操作系统 八股文

操作系统的特征?

  • 并发 并发指的是两个或多个事件在同⼀时间间隔内发⽣,计算机系统中同时存在多个运⾏的程序,因此具有处理和调度多个程序同时执⾏的能⼒。
  • 共享: 系统中的资源可以供内存中多个并发执⾏的进程共同使⽤。
    • 互斥共享: ⼀段时间内只允许⼀个进程访问该资源。⼀段时间内只允许⼀个进程访问的资源称为临界资源。
    • 同时访问: ⼀段时间内允许多个进程“同时”访问,“同时”通常是宏观的,实际上是交替的对该资源进⾏访问。
  • 虚拟:把⼀个物理上的实体变为若⼲逻辑上的对应物。
  • 异步: 进程的执⾏并不是⼀贯到底的,⽽是以不可预知的速度向前推进。

局部性原理?

在⼀段时间内,程序倾向于多次访问相同的数据或接近的数据,⽽不是随机地访问内存中的各个位置。局部性原理通常分为两种类型:时间局部性和空间局部性。

1. 时间局部性

如果⼀个数据被访问,那么在不久的将来它很可能会再次被访问。这意味着程序在短时间内倾向于反复使⽤相同的数据项,例如在循环中反复访问数组的元素。 通过利⽤时间局部性,程序可以将频繁使⽤的数据存储在缓存中,从⽽减少访问主内存的次数,提⾼程序的执⾏速度。

2. 空间局部性

如果⼀个数据被访问,那么它附近的数据也很可能会被访问。这意味着程序在访问⼀个数据时,通常会在接近该数据的附近访问其他数据,例如遍历数组时,往往会访问相邻的元素。 ⽂件系统在磁盘上存储数据时,通常会将相关的数据块放在相邻的磁盘扇区上,以便在访问⼀个数据块时能够快速地访问相邻的数据块。

信号和信号量有什么区别?

信号: ⼀种处理异步事件的⽅式。信号是⽐较复杂的通信⽅式,⽤于通知接收进程有某种事件发⽣,除了⽤于进程外,还可以发送信号给进程本身。

信号量: 进程间通信处理同步互斥的机制。是在多线程环境下使⽤的⼀种设施,它负责协调各个线程,以保证它们能够正确,合理的使⽤公共资源。

线程和进程的区别?

  1. 资源方面: 进程是系统中拥有资源的基本单位,⽽线程不拥有系统资源(仅有⼀点必不可少的能保证运⾏的资源,⽐如寄存器和栈),但线程可以访问⾪属进程的系统资源。

  2. 调度方面: 进程是系统调度的基本单位。线程是操作系统能偶进行运算调度的最小单位。线程切换的代价远低于进程,在同⼀个进程中,线程的切换不会引起进程切换,⽽从⼀个进程中的线程切换到另⼀个进程中的线程中,会引起进程切换。

  3. 独立性方面: 每个进程都拥有独⽴的地址空间和资源、除了共享全局变量,不允许其他进程访问。某进程中的线程对其他进程都不可⻅,同⼀进程中的不同线程是为了提⾼并发性以进⾏相互之间的合作⽽创建的,它们共享进程的地址空间和资源。

  4. 系统开销方面: 线程所需要的开销⽐进程⼩

    • 线程的创建时间⽐进程快,因为进程在创建的过程中,还需要资源管理信息,⽐如内存管理信息、⽂件管理信息,⽽线程在创建的过程中,不会涉及这些资源管理信息,⽽是共享它们;
    • 线程的终⽌时间⽐进程快,因为线程释放的资源相⽐进程少很多;
    • 同⼀个进程内的线程切换⽐进程切换快,因为线程具有相同的地址空间(虚拟内存共享),这意味着同⼀个进程的线程都具有同⼀个⻚表,那么在切换的时候不需要切换⻚表。⽽对于进程之间的切换,切换的时候要把⻚表给切换掉,⽽⻚表的切换过程开销是⽐较⼤的。
    • 由于同⼀进程的各线程间共享内存和⽂件资源,那么在线程之间数据传递的时候,就不需要经过内核了,这就使得线程之间的数据交互效率更⾼。
  5. 安全方面: 由于进程之间相互隔离,一个进程的崩溃不会直接影响到其他进程的稳定性;而线程由于共享相同的内存空间,一个线程的错误可能会影响整个进程的稳定性。

  6. 通信方面: 线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC(进程通信技术)进行通信。

进程间的通信方式有哪些?

总的来说,进程之间通信的方式有六种,分别是管道、消息队列、信号、信号量和共享内存和Socket。

管道通信:

在Linux和类Unix系统中,管道是一种特殊的文件描述符,它可以连接一个进程的输出和另一个进程的输入,从而实现进程间的单向通信。管道通信又分为匿名管道和有名管道。

匿名管道:

一个单工的通信模式,具有固定的读端和写端,只能用于具有亲缘关系的进程之间通信,用完既销毁。匿名管道用 fork() 函数创建,可以将他看成一种特殊文件,对他的读写可以使用 read(),write() 函数;

命名管道:

该管道可通过路径名指出,在文件系统中可见,可以使两个相关的进程实现彼此通信,严格遵守先进先出的规则,在开始处读数据,末尾处写数据。命名管道用 mkfifo()函数创建;

  • 管道通信虽然简单,但是效率比较地,不适合进程间频繁地交换数据,并且管道智能传输无格式的字节流。

消息队列通信:

当A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程在需要的时候自行去消息队列中读取数据就可以了。同样的,B 进程要给 A 进程发送消息也是如此。消息队列的本质就是存放在内存中的消息的链表, 而消息本质上是用户自定义的数据结构。如果进程从消息队列中读取了某个消息,这个消息就会被从消息队列中删除。

  • 消息队列允许一个或多个进程向他写入或者读取信息;

  • 消息队列可以实现消息的随机查询,不一定非要以先进先出的次序读取消息,也可以按消息的类型读取。比有名管道的先进先出原则更有优势;

  • 消息队列对于交换较少数量的数据很有用,因为无需避免冲突。但是,由于用户进程写入数据到内存中的消息队列时,会发生从用户态拷贝数据到内核态的过程;同样的,另一个用户进程读取内存中的消息数据时,会发生从内核态拷贝数据到用户态的过程。因此,如果数据量较大,使用消息队列就会造成频繁的系统调用,也就是需要消耗更多的时间以便内核介入。

共享内存通信:

共享内容可以很好的解决消息队列频繁的系统调用的问题。共享内存允许不相干的进程同一段物理内存连接到它们各自的地址空间中,使得这些进程可以访问同一个物理内存,这个物理内存就成为共享内存。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程

  1. 每个进程都有属于自己的进程控制块(PCB)和逻辑地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的逻辑地址(虚拟地址)与物理地址进行映射,通过内存管理单元(MMU)进行管理。

  2. 两个不同进程的逻辑地址通过页表映射到物理空间的同一区域,它们所共同指向的这块区域就是共享内存。

  3. 共享内存机制仅在建立共享内存区域时需要系统调用,一旦建立共享内存,所有的访问都可作为常规内存访问,无需借助内核。这样,数据就不需要在进程之间来回拷贝,所以这是最快的一种进程通信方式。

信号量通信:

信号量其实是⼀个整型的计数器,主要⽤于实现进程间的互斥与同步,⽽不是⽤于缓存进程间通信的数据。可以⽤来控制多个进程对共享资源的访问,常作为⼀种锁机制,防⽌某进程正在访问共享资源时,其他进程也访问该资源。因此主要作为进程间以及同⼀进程内不同线程之间的同步⼿段。

控制信号量有两种操作,一种是P操作,一种是V操作

  • P 操作,这个操作会把信号量减去 1,相减后如果信号量 < 0,则表明资源已被占⽤,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使⽤,进程可正常继续执⾏;

  • V 操作,这个操作会把信号量加上 1,相加后如果信号量 <= 0,则表明当前有阻塞中的进程,于是会将该进程唤醒运⾏;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;

信号通信:

⽤于通知接收进程某个事件已经发⽣,从⽽迫使进程执⾏信号处理程序,这也是一种信号通信的方式。信号是进程通信机制中唯一的异步通信机制,它可以在任何时候发送信号给某个进程。通过发送指定信号来通知进程某个异步事件的发送,以迫使进程执行信号处理程序。信号处理完毕后,被中断进程将恢复执行。用户、内核和进程都能生成和发送信号。

  • 信号事件的来源主要有硬件来源软件来源

  • 所谓硬件来源就是说我们可以通过键盘输入某些组合键给进程发送信号,比如常见的组合键 Ctrl+C 产生 SIGINT 信号,表示终止该进程;

  • 而软件来源就是通过 kill 系列的命令给进程发送信号,比如 kill -9 1111 ,表示给 PID 为 1111 的进程发送 SIGKILL 信号,让其立即结束。可通过 kill -l命令查看所有信号;

Socket通信:

上面介绍的5种方法都是用于同一台主机上的进程之间进行通信的,如果想要跨网络与不同主机上的进程进行通信就得使用 Socket 通信了。Socket 是支持TCP/IP的网络通信的基本操作单元,主要用于在客户端和服务器之间通过网络进行通信。

Windows间的进程通信方式?

文件映射、共享内存、管道、邮件槽、粘贴板和远程过程调用。

线程间的通信方式?

同个进程下的线程之间都是共享进程的资源,只要是共享变量都可以做到线程间通信,⽐如全局变量,所以对于线程间关注的不是通信⽅式,⽽是关注多线程竞争共享资源的问题,信号量也同样可以在线程间实现互斥与同步

  1. 互斥锁: 互斥锁是最常⻅的线程同步机制。它允许只有⼀个线程同时访问被保护的临界区(共享资源);

  2. 条件变量: 条件变量⽤于线程间通信,允许⼀个线程等待某个条件满⾜,⽽其他线程可以发出信号通知等待线程。通常与互斥锁⼀起使⽤;

  3. 读写锁: 读写锁允许多个线程同时读取共享资源,但只允许⼀个线程写⼊资源;

  4. 信号量: ⽤于控制多个线程对共享资源进⾏访问的⼯具。

进程的内存分布是怎么样的?

在操作系统中,每个进程都有自己独立的内存空间,这个内存空间通常被划分为几个不同的区域,包括:

代码段(Text Segment): 存储程序的机器指令,通常是只读的,用于存放可执行程序的机器代码。

数据段(Data Segment): 储全局变量和静态变量,包括初始化的全局变量、静态变量、常量,以及未初始化的全局变量和静态变量,该段可以分为只读数据段和可读写数据段。

堆(Heap): 动态分配的内存空间,由程序员手动管理,用于存放动态分配的内存块,比如使用malloc或new分配的内存。

栈(Stack): 存储局部变量、函数参数、函数返回地址等,由编译器自动管理,每次函数调用时会在栈上分配一定的空间,函数返回时释放该空间。

内核空间(Kernel Space):用于存放操作系统内核的数据结构和代码,普通用户进程无法直接访问。

介绍一下你认识的锁?

锁是一个抽象概念,是一种保护共享资源的同步化技术。锁有两个操作:acquirerelease。它一次最多只允许一个线程获取,一旦所有权被某一线程获取,其他线程只能等待该线程释放锁才能访问被保护的资源。

根据线程调度方式,可以将锁分为互斥锁和自旋锁;

互斥锁

一个 CPU 上面的多个线程抢占一把锁,抢占失败的线程会被调度器置位 WAIT (睡眠)状态,直到下一次的 CPU 时间片到来时再次抢占。互斥锁适用于加锁时间较长的场景,此时线程上下文切换带来的开销可以被忽略。

自旋锁

线程获取自旋锁失败后,不会放弃 CPU,会一直处于忙等待状态并持续检查锁是否被释放。适用于加锁时间小于线程切换开销的场景。

数据库中常见的两种锁是悲观锁和乐观锁。

悲观锁

悲观锁很悲观,它认为多线程同时修改共享资源的概率⽐较⾼,所以访问共享资源的时候先上锁;

乐观锁

乐观锁没有那么悲观,它假设数据一般情况不会造成冲突,即使当多用户同时修改数据后,只有一条被记录。当数据进行提交更新的时候,如果检测到数据不匹配,此时上报错误信息。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量

最后一种是读写锁

读写锁

读写锁用于对共享资源的访问,它允许多个线程同时读共享资源,但在有线程要写共享资源时必须互斥排斥其他读者和写者。

读写锁有两种状态:读模式和写模式。在读模式下可以有多个线程同时访问共享资源,而在写模式下只能有一个线程访问共享资源。当有线程在写模式下访问共享资源时,所有其他线程(无论读模式还是写模式)都会被阻塞,直到写操作完成。

读写锁的好处是可以提高读并发性能。当共享资源被频繁读取而很少被写入时,读写锁可以允许更多线程并发地读取数据,从而提高系统的吞吐量和性能。

你知道死锁吗?什么情况下会产生死锁?

死锁是指两个或多个进程在争夺系统资源时,由于互相等待对⽅释放资源⽽⽆法继续执⾏的状态。死锁只有同时满⾜以下四个条件才会发⽣:

  1. 互斥条件 ⼀个进程占⽤了某个资源时,其他进程⽆法同时占⽤该资源;
  2. 请求和保持 一个线程因为请求资源而阻塞的时候,不会释放自己的资源;
  3. 不可剥夺条件 资源不能被强制性地从⼀个进程中剥夺,只能由持有者⾃愿释放;
  4. 环路等待条件 多个进程之间形成⼀个循环等待资源的链,每个进程都在等待下⼀个进程所占有的资源;

如何解除死锁呢?

只需要破坏上⾯⼀个条件就可以破坏死锁。

  • 破坏请求与保持条件 一次性申请所有的资源;
  • 破坏不可剥夺条件 占⽤部分资源的线程进⼀步申请其他资源时,如果申请不到,可以主动释放它占有的资源;
  • 破坏循坏等待条件 靠按序申请资源来预防。让所有进程按照相同的顺序请求资源,释放资源则反序释放;

或曰

预防死锁: 通过破坏死锁产生的四个条件之一,来预防死锁的发生。例如,只允许进程一口气获取它所需的全部资源,或者按照一定的顺序获取资源。

避免死锁: 在资源分配过程中,用某种方法避免系统进入不安全状态,避免死锁的产生。采用银行家算法判断是否存在安全序列;

检测死锁: 通过周期性地检测系统中是否存在死锁,来及时发现和解除死锁。

解除死锁: 当死锁发生时,可以剥夺某些进程的资源、强制撤销部分或者全部死锁进程和让一个或多个进程回退到不足以发生死锁的地步。

进程的调度算法有哪些?

批处理系统中的调度:

先来先服务

⾮抢占式的调度算法,按照请求的顺序进⾏调度。有利于⻓作业,但不利于短作业,因为短作业必须⼀直等待前⾯的⻓作业执⾏完毕才能执⾏,⽽⻓作业⼜需要执⾏很⻓时间,造成了短作业等待时间过⻓。

最短作业优先

⾮抢占式的调度算法,按估计运⾏时间最短的顺序进⾏调度。 ⻓作业有可能会饿死。 处于⼀直等待短作业执⾏完毕的状态。因为如果⼀直有短作业到来,那么⻓作业永远得不到调度。

最短剩余时间优先

最短作业优先的抢占式版本,按剩余运⾏时间的顺序进⾏调度。当⼀个新的作业到达时,其整个运⾏时间与当前进程的剩余时间作⽐较。如果新的进程需要的时间更少,则挂起当前进程,运⾏新的进程。否则新的进程等待。

交互系统中的调度

时间片轮转调度

将所有就绪进程按FCFS的原则排成一个队列,每次调度时,把 CPU 时间分配给队⾸进程,该进程可以执⾏⼀个时间⽚。当时间⽚⽤完时,由计时器发出时钟中断,调度程序便停⽌该进程的执⾏,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队⾸的进程。

优先级调度

为每个进程分配⼀个优先级,按优先级进⾏调度。为了防⽌低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。

多级调度队列

⼀个进程需要执⾏ 100 个时间⽚,如果采⽤时间⽚轮转调度算法,那么需要交换 100 次。 多级队列是为这种需要连续执⾏多个时间⽚的进程考虑,它设置了多个队列,每个队列时间⽚⼤⼩都不同,例如1,2,4,8,..。进程在第⼀个队列没执⾏完,就会被移到下⼀个队列。这种⽅式下,之前的进程只需要交换 7 次。

每个队列优先权也不同,最上⾯的优先权最⾼。因此只有上⼀个队列没有进程在排队,才能调度当前队列上的进程。可以将这种调度算法看成是时间⽚轮转调度算法和优先级调度算法的结合。

最短进程优先

如果我们将每⼀条命令的执⾏看作是⼀个独⽴的“作业”,则我们可以通过⾸先运⾏最短的作业来使响应时间最短。

分段和分页的区别?

  • 基本单位: 分段将地址空间被划分为不同的逻辑段,每个段具有独⽴的含义,如代码段、数据段等。分页将地址空间被划分为固定⼤⼩的⻚⾯,物理内存也被划分为相同⼤⼩的⻚⾯框。
  • 长度: 每个段的⻓度可以动态变化,不同段的⻓度可以不同。⻚⾯的⻓度是固定的,由操作系统定义。
  • 碎片: 分段和分页都有可能产生内部碎片和外部碎片。
  • 逻辑地址: 逻辑地址由两部分组成,⼀个是段号,另⼀个是段内偏移。逻辑地址由两部分组成,⼀个是⻚号,另⼀个是⻚内偏移。

说说页面置换算法?

LRU 最近最少使用算法

每次选择最⻓时间没有被使⽤的⻆⾊进⾏切换。这种策略基于你对⻆⾊的喜好, 认为最近被使⽤过的⻆⾊很可能还会被使⽤,⽽最久未被使⽤的⻆⾊很可能不会再被使⽤。LRU算法可以有效地减少切换次数,但是实现起来⽐较复杂,需要记录每个⻆⾊的使⽤时间或者维护⼀个使⽤顺序的列表。LRU一般用哈希表加双向链表实现。

FIFO 先进先出算法

每次选择最早进⼊内存的⻆⾊进⾏切换。这种策略很简单,只需要维护⼀个⻆⾊队 列,每次淘汰队⾸的⻆⾊,然后把新的⻆⾊加⼊队尾。但是FIFO算法可能会淘汰⼀些经常被使⽤的⻆⾊,导致切换次数增加。⽽且FIFO算法有可能出现⻉拉迪异常(Belady anomaly),即当分配给内存的空间增加时,切换次数反⽽增加。

OPT 最佳页面置换算法

置换在未来最⻓时间不访问的⻚⾯,但是实际系统中⽆法实现,因为程序访问⻚⾯时是动态的 我们是⽆法预知每个⻚⾯在下⼀次访问前的等待时间,因此作为实际算法效率衡量标准。

时钟⻚⾯置换算法

把所有的⻚⾯都保存在⼀个类似钟⾯的环形链表中,⻚⾯包含⼀个访问位。当发⽣缺⻚中断时,顺时针遍历⻚⾯,如果访问位为1,将其改为0,继续遍历,直到访问到访问位为0⻚⾯,进⾏置换。

最不常用算法

记录每个⻚⾯访问次数,当发⽣缺⻚中断时候,将访问次数最少的⻚⾯置换出去,此⽅法需要对每个⻚⾯访问次数统计,额外开销。




什么是中断和异常?

由CPU内部产生的意外事件称为异常,也叫内中断。由CPU外部的设备向CPU发出的中断请求称为中断 ,也叫外中断

中断和异常都会导致处理器暂停当前正在执⾏的任务,并转向执⾏⼀个特定的处理程序(中断处理程序或异常处理程序)。然后在处理完这些特殊情况后,处理器会返回到被打断的任务继续执⾏。

中断

中断是由计算机系统外部事件触发的,通常与硬件设备相关。中断的⽬的是为了及时响应重要事件暂时中断正常的程序执⾏。典型的中断包括时钟中断、I/O设备中断(如键盘输⼊、⿏标事件)和硬件错误中断等。中断可分为可屏蔽中断和不可屏蔽中断。

异常

异常 是由计算机系统内部事件触发的,通常与正在执⾏的程序或指令有关,⽐如程序的⾮法操作码、地址越界、运算溢出等错误引起的事件,异常不能被屏蔽,当出现异常时,计算机系统会暂停正常的执⾏流程,并转到异常处理程序来处理该异常。按异常发生的方式和返回方式的不同,异常可分为故障、自陷和终止。

中断和异常发生后,会进入异常处理阶段。

  1. 执行关中断指令,避免当前中断被新的中断中断;
  2. 保存断点,比如PC寄存器的内容;
  3. 引出中断服务程序;
  4. 保存现场和屏蔽字;现场就是用户可兼得寄存器内容;
  5. 开中断(如果支持多重中断的话);
  6. 执行中断服务程序;
  7. 关中断(对应多重中断中的开中断);
  8. 恢复现场和屏蔽字;
  9. 开中断,中断返回;

什么是孤儿进程和僵尸进程?

孤⼉进程: ⼀个⽗进程退出,⽽它的⼀个或多个⼦进程还在运⾏,那么那些⼦进程将成为孤⼉进程。孤⼉进程将被 init 进程(进程号为1)所收养,并由 init 程对它们完成状态收集⼯作。

僵⼫进程: ⼀个进程使⽤ fork 创建⼦进程,如果⼦进程退出,⽽⽗进程并没有调⽤ waitwaitpid 获取⼦进程的状态信息,那么⼦进程的进程描述符仍然保存在系统中。这种进程称之为僵⼫进程。

什么是内存碎片?

内存碎片是指已分配的内存空间中存在未被使用或无法利用的小块零散内存。它可以分为两种类型:外部碎片和内部碎片。

外部碎片是指已分配的内存块之间的零散空闲内存,由于这些空闲内存不连续,无法被利用。而内部碎片是指已分配的内存块中有部分空间未被使用,导致浪费。

有什么办法解决内存碎片吗?

  1. 内存紧缩(Memory Compaction):内存紧缩是一种重排已分配内存块的方法,将所有已分配的内存块向一端移动,以便形成一个较大的连续内存块。这样可以解决外部碎片问题,并提供更大的连续内存空间。

  2. 分区合并(Partition Coalescing):当有连续的空闲内存块相邻时,可以将它们合并成一个更大的空闲内存块,从而减少外部碎片。这通常在内存回收时进行。

当我申请一块内存空间时,为什么系统有足够大的空间却申请失败?

因为存在了大量的外部碎片,导致无法申请一块满足条件的连续的内存块。

如何管理内存空间?

  1. 空闲列表(Free List): 操作系统通常会维护一个空闲列表,记录可用的内存块。当有进程请求内存时,操作系统会从空闲列表中找到一个足够大的内存块分配给该进程。空闲列表可以使用链表、位图或其他数据结构来实现。

  2. 首次适应算法(First Fit Algorithm): 首次适应算法是一种简单的内存分配策略,它从空闲列表中找到第一个足够大的内存块分配给进程。这种算法的优点是分配速度快,但可能会导致内存碎片化问题。

  3. 最佳适应算法(Best Fit Algorithm): 最佳适应算法选择空闲列表中最小的足够大的内存块进行分配。这种算法可以减少内存碎片化的问题,但需要遍历整个空闲列表,分配速度较慢。

  4. 最差适应算法(Worst Fit Algorithm): 最差适应算法选择空闲列表中最大的足够大的内存块进行分配。这种算法可以减少大型内存块的浪费,但可能会导致较大的内存碎片化。

  5. 快速适应算法(Quick Fit Algorithm): 快速适应算法是一种结合了首次适应和最佳适应算法的策略。它将内存划分为几个大小相等的块,并为每个块维护一个空闲列表。当有进程请求内存时,操作系统先在对应大小的块的空闲列表中找到合适的内存块进行分配。

  6. 内存回收: 当进程释放内存时,操作系统需要将该内存块标记为空闲,并将其加入到空闲列表中。如果相邻的空闲内存块存在,则可以考虑合并它们,以减少内存碎片。

虚拟地址是怎么变到物理地址的?

在操作系统中,虚拟地址到物理地址的映射是通过内存管理单元MMU来实现的。MMU是计算机硬件中的一个组件,负责管理虚拟地址和物理地址之间的转换。

  1. CPU将虚拟地址并发送给 MMU
  2. MMU 根据虚拟地址的高位找到对应的页表项。
  3. 从页表项中获取物理地址的高位。将虚拟地址的低位作为偏移量,加上物理地址的高位,得到最终的物理地址。
  4. MMU 将物理地址返回给CPU,CPU使用物理地址访问内存。

通过这种虚拟地址到物理地址的映射机制,操作系统实现了虚拟内存管理,提高了内存的利用效率,并为程序提供了更大的地址空间。

IO多路复用了解吗?

先答io多路复用是什么,再答select、poll、epoll

IO多路复用是一种同步的IO模型,利用IO多路复用模型,可以实现一个线程监视多个文件句柄。一旦某个文件句柄就绪,就能够通知到对应的应用程序进行相应的读写操作;如果没有句柄就绪时,就会阻塞应用程序,从而释放出CPU资源。 实现IO多路复用的原型有三种,select、poll、epoll