# 操作系统

# 1.CPU如何保持缓存和内存的数据一致

答案

有两种方式,写直达和写回

写直达:首先判断该数据是否存在Cache中,如果存在,则写入Cache,再写入内存。否则直接写入内存

写回:首先判断该数据是否存在Cache中,如果存在,则直接写入Cache,将其标记为脏。如果不存在,定位到对应的Cache块,如果该块为脏,则先将其写入内存,然后再将要写入的数据从内存读出(为了获取到cache对应内存中的位置,使得下次查找时,可以直接找到内存中的数据),再写入到Cache,标记为脏。如果该块不为脏,则将要写入的数据从内存读出,然后将要写入的数据写入Cache,并标记为脏

# 2.多核CPU如何保证缓存一致性

答案

通过基于总线嗅探机制的MESI协议,维护了已修改,独占,共享,已失效四个状态。根据来自本地核心的请求,或者是来自其他CPU核心通过总线传输过来的请求,从而构成一个流动的状态机,对于处于已修改或独占状态的CacheLine,修改数据时,不需要发送广播给其他CPU核心

MESI协议保证了缓存一致性

1.它实现了基于总线嗅探机制实现了写传播

2.它基于状态机实现了事务的串行化(当一个核心修改了缓存行,其他核心都会将该缓存行设为无效,访问必须从内存中取)

# 3.什么是中断?

答案

中断是操作系统用来打断当前执行的进程,转而执行中断处理程序的一种机制

分为硬中断和软中断,硬中断是由硬件触发中断,用于快速处理中断。软中断,由内核触发中断,用来异步的完成硬中断没完成的工作

# 4.为什么要有虚拟内存

答案

1.虚拟内存使得进程的运行内存可以超过物理内存的大小,因为程序符合局部性原理,CPU访问内存会有很明显的重复访问的倾向性,对于那些没有经常访问的数据,我们可以将其换出物理内存

2.虚拟内存使得每个进程都有自己的页表,每个进程的虚拟内存空间都是独立的,解决了多进程地址空间冲突的问题

3.虚拟内存的页表中记录了一个页的读写权限,在内存访问方面,为操作系统提供了更好的安全性

# 5.内存分段机制

答案

内存分段机制将一个程序分成多个逻辑段,如代码段,栈段,堆段,数据段,每个段有自己的属性,分段机制下,虚拟地址由段选择因子和段内偏移组成。段选择因子包括段号,段的界限,段的特权等级。

# 6.内存分页机制

答案

将整个虚拟内存和物理内存都分成固定大小的页,页与页之间是紧密排列的,不会有外部碎片。分页机制下,虚拟地址由页号和页内偏移量组成,然后通过页表,将虚拟地址中的页号映射到物理页号。

# 7.内存分段和分页机制的缺点

答案

分段机制的缺点是容易产生外部碎片,内存交换效率低(因为容易产生外部碎片,所以经常需要将数据交换到磁盘,但是磁盘访问速度太慢,所以会导致内存交换效率很低)

分页机制的缺点是容易产生内部碎片(因为分页机制的最小单位是页,所以即使程序不足一页,也只能分配一页)

# 8.分页机制如何解决外部碎片和内存交换效率低的问题?

答案

出现外部碎片是因为有比较小的内存无法分配的出去,而分页机制是固定大小,因此不会有外部碎片问题,当内存空间不足时,会将少数的一个或几个页换出到磁盘上,不会花太多时间,因此内存交换效率比较高

# 9.段页式机制

答案

先将程序划分成多个有逻辑意义的段,再将每个段分成多个页。每个程序一个段表,每个段由有一张页表,在段页式机制下,虚拟地址由段号,段内页号,页内偏移组成。

# 10.malloc通过brk()和mmap()申请内存的区别

答案

通过brk()方式申请内存时,free释放内存时,并不会把内存归还给操作系统,而是在malloc的内存池中,待下次使用

通过mmap()方式申请内存时,free释放内存时,会把内存归还给操作系统,内存得到真正的释放

# 11.为什么不全部使用 mmap 来分配内存?

答案

因为使用mmap分配内存会导致每次都发生运行态的切换,还会导致缺页中断,会导致CPU消耗太大

# 12.为什么不全部使用 brk来分配内存?

答案

brk分配内存很容易造成内存碎片,对于小块内存,堆内会产生越来越多的不可用的碎片,从而造成内存泄漏

# 13.malloc返回的地址结构

答案

包括内存的头信息和用户使用的内存块

# 14.内存回收机制

答案

当内存分配时,可分配内存不够就会触发后台内存回收,这个回收过程是异步的,然后检查是否有足够的空闲物理内存,如果还不够,则启用直接内存回收,这是同步的过程。如果还不够,则会触发OOM机制。内存回收的时候,对于文件页,如果是脏页,先写入磁盘,再回收,否则,直接回收,对于匿名页,先写入磁盘,再回收。在回收时,会从通过LRU算法,取出队尾的内存页,因为他是很少被访问的,将其回收

# 15.回收内存带来的影响

答案

1.对于后台内存回收,是异步回收的,因此不会阻塞进程

2.对于直接内存回收,是同步回收的,会阻塞进程,这会造成很长时间的延迟,以及系统的CPU利用率会升高,导致系统负载升高

# 16.在4g的机器上申请8g的内存会怎么样?

答案

首先要考虑是32位还是64位的操作系统,32位可申请的内存是3G,64位可申请的内存是128T。 如果超过对应的,将会申请失败。然后考虑是否访问内存,如果不访问,因为保存虚拟内存的数据结构需要内存,所以只要物理内存充足,就可以申请成功。如果物理内存不足,开启swap机制也可以申请成功。如果访问,超过物理内存后,不开启swap机制将会触发OOM。

# 17.swap机制

答案

当系统内存不足或大量内存闲置时,swap机制会将进程暂时不用的内存数据存储到磁盘中,并释放这些数据的内存。当进程再次访问这些内存时,再把它们从磁盘读到内存中来

# 18.linux如何避免预读失效和缓存污染

答案

linux是基于LRU算法,将其划分成活跃链表和非活跃链表,预读的页加入到非活跃链表的头部,当页被真正访问时,才将页插入活跃链表头部,如果预读的页没有被访问,也不会影响活跃链表中的热点数据

缓存污染是因为大量数据直接进入活跃链表,所以我们要提高进入活跃链表的门槛,因为大量的数据只会被读入一次,因为不会被加入到活跃链表,而造成热点数据被替换掉

# 19.进程虚拟空间的组成

答案

由栈,文件映射和匿名映射区,堆,BSS段,数据段,代码段组成。BSS段是未初始化的数据,文件映射和匿名映射区就是通过mmap申请的内存

# 20.用户空间和内核空间

答案

用户空间是应用程序的运行空间。内核空间是内核的运行空间, 进程在用户态时,只能访问用户空间。只有进入内核态,才能访问内核空间

# 21.进程上下文切换的过程

答案

首先会从用户态切换到内核态,然后保存进程上下文,然后加载另一个进程的进程上下文。

# 22.CPU上下文切换

答案

先将CPU上下文(CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到寄存器和程序计数器中,最后再跳转到程序计数器所指的新位置

# 23.进程上下文是什么?

答案

进程上下文包括进程的虚拟地址空间(堆,栈,代码段,数据段等),全局变量,进程控制块,寄存器,程序计数器等信息

# 24.什么是进程?什么是线程?什么是协程?

答案

进程是资源分配的最小单位,线程是cpu调度的最小单位。 进程是执行中的程序。线程是进程的一个执行流程。协程是一种用户态的,不被操作系统所管理的,完全由用户控制的,比线程更加轻量级的存在

# 25.进程和线程的区别?

答案

1.进程是资源分配的单位,线程是CPU调度的单位

2.进程拥有完整的资源,而线程只独享必不可少的资源,如寄存器和栈

3.进程上下文切换需要保存更多的上下文信息,而因为同一进程的线程共享了进程的信息,故需要保存的上下文更少

4.线程之间的访问需要进行协同和同步,否则会出现竞争条件和死锁

# 26.线程上下文切换

答案

如果两个线程属于同一个进程,则只需要切换线程的私有数据和寄存器等数据

如果两个线程不属于同一个进程,则和进程上下文切换一样。

# 27.线程和协程的区别

答案

1.线程的调度由操作系统控制,而协程的调度由用户自己控制

2.线程的切换需要由用户态切换到内核态,而协程的切换不需要

3.多核处理器的环境下,多线程可以是并行的,但是多协程是并发的

4.线程通常是抢占式的,而协程是协同式的。

# 28.进程调度算法

答案

进程调度算法包括先来先服务,最短作业优先,高响应比优先,时间片轮转,多级反馈队列,最高优先级

先来先服务对长作业有利,适合CPU密集型,不适合IO密集型的系统

最短作业优先,对长作业不利,可能导致长作业一直不能运行

高响应比优先权衡了短作业和长作业

最高优先级,可能会导致低优先级的作业永远无法运行

多级反馈队列,兼顾了长短作业,同时有较好的响应时间

# 29.页面置换算法

答案

最佳页面置换算法(太过理想没法实现,将未来最长时间不访问的页面置换)

最近最久未使用置换算法(LRU)

先进先出置换算法(FIFO)

时钟页面替换算法(维护一个环形链表,每个页面记录一个访问标志位,置换时,遇到访问标志位为1的就将其改成0,遇到0就将其置换,当页面被访问时,将标志位设为1

最不常用算法(LFU)

# 30.磁盘调度算法

答案

先来先服务

最短寻道时间优先

扫描算法(选定某一个方向,直到最后一个磁道,才调转方向,返回途中处理请求)

循环扫描算法(选定某一个方向,直到最后一个磁道,才调转方向,返回途中不处理请求)

LOOK算法(基于扫描算法的改进,磁头只会移动到最远的请求位置,然后立即反向移动,返回途中处理请求)

C-LOOK算法(基于循环扫描算法的改进,磁头只会移动到最远的请求位置,然后立即反向移动,返回途中不处理请求)

# 31.虚拟内存和物理内存的定义

答案

虚拟内存是一种内存管理技术,将程序使用的内存地址(虚拟地址)映射到物理内存的地址

物理内存就是实际使用的内存

# 32.select,poll,epoll

答案

select就是将已连接的socket列表拷贝到内核中,然后由内核检查是否有网络事件产生,通过遍历socket列表,然后将有网络事件产生的socket标记为可读或可写,然后再拷贝到用户态,用户态再遍历socket列表,找到可读或可写的socket,对其进行处理

poll就是将select使用的bitsmap替换成了链表,从而不会受到bitsmap长度的限制

epoll在内核中使用红黑树来关注进程所有待检测的socket,从而减少数据拷贝,使用事件驱动机制,内核里维护了一个链表来记录就绪事件,只将有事件发生的socket列表传递给应用程序,不需要扫描整个集合

# 33.用户态和内核态

答案

用户态是应用程序运行的状态,处于用户态时只能访问受限的内存

内核态是内核运行的状态,处于内核态时可以访问任何数据

# 34.操作系统进行内存管理的意义?

答案

1.优化内存使用效率

2.保证进程之间使用内存互不干扰,保证系统的安全性

3.更加高效的申请和释放内存

# 35.进程之间通信的方式,同一台主机哪个最快?

答案

1.匿名管道

本质上是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联。因为管道是单向流动的,因此实现进程之间的通信必须使用两个管道,管道是用环形队列实现的,数据从写端流入读端流出,这就实现父子进程之间的通信

2.有名管道

匿名管道由于没有名字,只能用于父子进程之间的通信,因此出现有名管道

3.消息队列

消息队列的本质就是存放在内存中的消息的链表,而消息本质上是用户自定义的数据结构,但消息队列只能用于数据量较少的场景,因为数据量较大,使用消息队列就会造成频繁的系统调用,也就是需要消耗更多的时间以便内核介入

4.信号

信号是进程通信机制中唯一的异步通信机制,它可以在任何时候发送信号给某个进程,通过发送指定信号来通知进程某个异步事件的发送以迫使进程执行信号处理程序。信号处理完毕后,被中断的进程将恢复执行

5.信号量

信号量是一个特殊的变量,它的本质是计数器,记录了临界资源的数目,用于协调进程对共享资源的访问,让临界区同一时间只有一个进程访问它,常与共享内存配合使用

6.共享内存

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

7.socket

socket本质上是一个编程接口,是应用层与TCP/IP协议族通信的中间软件抽象层,它对TCP/IP进行了封装,把复杂的TCP/IP协议族隐藏在Socket接口后面。常用于跨主机通信

同一台主机,使用共享内存最快,因为直接进行读写,一个进程写入共享内存,另一个进程就可以直接读到

# 36.阻塞io模型,非阻塞io模型,io复用模型,信号驱动io模型,异步io模型,同步io,异步io

答案

1.阻塞io模型:就是当发生io系统调用时,进程被阻塞,转到内核空间处理,直到整个io处理完毕才返回

2.非阻塞io模型:就是当发生io系统调用时,如果数据还没准备好,则直接返回,不阻塞进程。如果数据准备好了,则将数据从内核拷贝到用户空间,然后返回。

3.io复用模型:进程将需要监听的socket传递给select,然后阻塞在select上,当有socket就绪时,就会返回。然后通知进程进行IO系统调用将数据从内核拷贝到用户空间,然后返回

4.信号驱动io模型:当进程发起一个io操作时,会向内核注册一个信号处理函数,然后进程返回,不阻塞。然后当数据准备好时,发送信号给进程,然后进程通过信号处理函数,发起IO系统调用将数据从内核拷贝到用户空间

5.异步io模型:当进程发起一个io操作时,直接返回,不会阻塞,然后当数据准备好,并拷贝到用户空间后,通知进程,可以获取数据了

6.同步io:是指发起io调用时,会阻塞进程,直到io操作完成

7.异步io:是指发起io调用时到io操作完成都是异步的,不会阻塞进程

# 37.一个进程有什么数据段?

答案

代码段,数据段,栈区,堆区

# 38.同一个线程有哪些段可以共享的?

答案

可以共享代码段,数据段

# 39.栈区和堆区有什么区别?

答案

1.栈区的内存分配和释放是自动进行的。堆区的内存分配和释放是由程序员通过代码显示进行的

2.栈区主要存储函数参数,局部变量。堆区存储程序运行过程中动态分配的内存

3.栈区的内存比堆区小的多

4.栈区内存分配和释放的速度非常快,但空间有限。堆区的内存分配和释放比较慢,且容易产生碎片,但可以提供较大的存储空间

# 40.使用共享内存要注意什么问题?

答案

1.多进程访问共享内存,必须使用适当的同步机制(如互斥锁,信号量等)来协调这些进程的访问,防止数据不一致和竞态条件

2.共享内存区域不会自动回收,使用完毕后必须显示回收,以避免内存泄漏

3.确保使用共享内存之前已经被初始化,避免不确定的行为

# 41.CPU如何读写磁盘

答案

1.读取:CPU向DMA发起IO请求,然后CPU去做其他工作,DMA负责向磁盘发起IO操作,但数据放入磁盘缓冲区后,通知DMA控制器,DMA控制器将数据冲磁盘缓冲区拷贝到内核缓冲区,然后向CPU发送数据读完信号,CPU再将内核缓冲区中的数据拷贝到用户缓冲区。

2.写入:

# 42.DMA的作用

答案

使得cpu不必将数据从磁盘缓冲区拷贝到内核缓冲区。这些都由DMA控制器完成

# 43.系统调用过程

答案

当用户程序执行到一个需要进行系统调用的节点的时候,该程序将对应的系统调用号,中断向量号等信息存入寄存器,然后调用ecall陷入内核态,切换保存上下文信息,接着触发硬件自动关闭中断(也可以软件实现关中断,但是用户就可以修改对应代码,不如硬件支持关中断安全,另一方面就是硬件直接支持的话速度更快,开销更少),此时有一个问题,用户态页表已经切换为了内核态页表,调用栈指针也切换为了内核态的,但是内核不知道下一条需要执行的内核页表指令是什么,这里的解决办法是内核虚拟内存和用户虚拟内存有一段相同的程序段tranpoline,切换到内核态后可以继续执行tranpoline,该程序段会调用usertrap(位于内核态负责调用用户需要的系统调用的一个中转程序),该程序会查看用户程序提前设置好的寄存器里的系统调用号等信息,去执行编写代码阶段提前注册好的中断处理程序,处理完成之后该程序负责开启中断(开启中断由软件层面实现)以继续接收中断,保存上下文信息,返回用户态,至此一次系统调用结束。

# 44.什么是IO多路复用?

答案

IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。

# 45.线程上下文

答案

栈,程序计数器,寄存器,线程优先级和调度信息等

# 46.线程调度的过程

答案

1.选择调度算法

2.确定优先级

3.创建和管理线程队列

4.上下文切换

5.执行线程

# 47.线程什么时候会阻塞

答案

1.线程休眠

2.等待获取锁

3.等待相关资源

4.读写数据

5.其他线程操作

# 48.死锁避免和死锁预防的方法

答案

死锁避免:

1.银行家算法

2.资源分配图算法

死锁预防:

1.确保至少有一种资源是可以共享的

2.进程一开始就申请所有需要的资源,或者在申请新资源时释放已占有的资源来实现。

3.通过让系统允许资源被剥夺并分配给其他进程

4.确保系统中的资源分配顺序是严格的,以便所有进程按顺序申请资源

# 49.多级页表的原理

答案

基于程序局部性原理,通过多级页表将页表分成多级,对于没有访问的页表,换出到磁盘,从而实现节省内存

# 50.公平锁和非公平锁

答案

公平锁:多个线程按照申请锁的顺序去获取锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁

优点:所有线程都能够得到锁,不会饿死在队列中 缺点:吞吐量会下降很多,除了第一个线程,其他线程都会阻塞,CPU唤醒阻塞线程的开销会很大

非公平锁:多个线程去获取锁时,会直接去尝试获取,获取不到,再进入等待队列,如果能获取到时,就直接获取到锁

优点:可以减少CPU唤醒线程的开销,提高吞吐量 缺点:可能导致队列中尾部线程饿死,一直拿不到锁

# 51.操作系统是如何执行程序的?

答案

首先操作系统会进行程序的装载,创建一个进程结构,包括栈,堆页表等,并进行初始化。此时代码还在磁盘中,在页表中只会记录代码在磁盘中的位置

然后进程会进入就绪状态,等待操作系统调度。

当进程被调度时,CPU会从程序入口取指令,但是这是一个虚拟地址,然后从页表中寻找,触发缺页中断,然后去磁盘中找,找到后会记录在页表中

当进程的时间片被用完的时候会被挂起,等待操作系统调度

当进程执行完成后,会将内存中的数据清理

# 52.为什么栈比堆快?

答案

1.栈是预分配内存的,因此在申请内存的时候几乎不需要时间。而堆是动态申请内存的。

2.栈的地址都是连续的,而堆不一定

3.cpu有专门的寄存器来操作栈,而堆是间接寻址的

4.栈是线程独享的,而堆是共享的,需要协同和同步

5.栈是在一级缓存中做的,而堆是在二级缓存中做的。

# 53.操作系统内存分配

答案

1.连续分配

固定分区分配:

由于没有根据需要的内存来分配分区大小,会产生很多的内部碎片

动态分区分配:

不会预先划分内存分区,动态的建立刚好合适的内存分区。即通过表记录空闲分区或空闲分区链

问题:会存在外部碎片,必须通过内存拼凑技术来解决,即将空闲的内存空间合并在一起,但是需要搬迁内存,开销较大

动态分区分配算法包括4种,首次适应算法,最佳适应算法,最小适应算法,邻近适应算法

首次适应算法即从低地址到高地址开始找,找到第一个符合条件的空闲分区

最佳适应算法即将空闲分区按容量从大到小排列,找到第一个符合条件的空闲分区,使得大内存进来能够有分区存放

问题:会产生越来越多小的,难以利用的内存块,即外部碎片

最大适应算法即将空闲分区按容量从小到大排列,找到第一个符合条件的空闲分区,避免剩余分区太小导致无法利用

问题:可能导致大内存分配不到

邻近适应算法即对首次适应算法的改进,将内存分配按地址递增排列构成一个循环链表,每次从上次查找完的位置开始,使得低地址和高地址都等概率的被使用,可能导致所有大分区都被分成小分区,从而无法分配大内存

2.非连续分配

分页存储管理:

将内存分成一个个页框,然后每个进程有一个页表,通过页表记录虚拟页号对应的物理页号,

分段存储管理:

段页存储管理:

# 54.malloc原理

答案

如果申请内存小于128K会采用brk,否则会采用mmap

brk本质上就是维护一个brk指针,表示已经使用的最后一个堆地址,当free的时候不会归还给操作系统而是放入malloc缓冲池

mmap本质上就是维护了一个空闲内存链表和一个红黑树,用于找到合适的内存,当free的时候会归还给操作系统

mmap每次都是新申请的一块内存,每次都会发生系统调用和缺页异常,因此性能很差0

# 55.cpu访问内存的全流程

答案

首先cpu拿到的是虚拟地址,首先会通过快表直接查询到物理地址,如果快表中没有,则从虚拟地址中获得虚拟页号和页内偏移。然后查询页表,得到物理页号,然后访问内存。

如果页表中没有,则触发缺页异常,会去物理内存中申请,首先会根据伙伴系统算法找到合适的物理内存,并将对应的信息写到页表和快表中

# 56.使用socket编程写一个tcp服务

答案

多线程模型:

对于一个tcp服务,首先调用socket接口创建一个socket,底层会生成一个文件描述符,用来表示该socket,然后调用bind绑定一个ip+端口,调用listen监听这个ip+端口的数据包,同时会在内核中创建半连接队列和全连接队列,accept函数会从全连接队列中取出已经完成三次握手的一个文件描述符,他是一个新创建socket。然后调用read读取数据,当读到eof的时候调用close关闭socket。同时为了实现支持多客户端,一般会使用多线程技术

io多路复用:

首先调用socket接口创建一个socket名为listenfd,底层会生成一个文件描述符,用来表示该socket,然后调用bind绑定一个ip+端口,调用listen监听这个ip+端口的数据包,同时会在内核中创建半连接队列和全连接队列,然后调用epoll_create接口获得一个epollfd,然后调用epoll_ctrl接口将listenfd注册到epollfd中,然后循环调用epoll_wait,当返回的时候会获得有读事件发生的fd列表,然后遍历这个列表,如果fd[i] == listenfd,说明是有新的连接建立了,则调用accept接口从全连接队列取出一个clientfd,然后将其注册到epollfd中去,如果!=listenfd,如果时间是读事件则调用recv读取数据,并调用write写数据

socket的send接口本质上是将数据拷贝到发送缓冲区(内存中的一块区域),然后调用操作系统的发送接口,将其发送给网卡,再传递到服务端网卡

socket的recv接口本质上是调用操作系统的接收接口,由操作系统通过网卡接收数据,将其拷贝到接收缓冲区,应用程序再从接收缓冲区读取数据

socket的close接口本质上是将socket的引用计数-1,当引用计数变成0时才会彻底关闭socket。即对于读方向将socket设置为不可读,对写方向,将发送缓冲区的数据发送给对端并进行四次挥手

socket的shutdown接口可以选择关闭读方向或写方向或都关闭,对于关闭读方向会将将接收缓冲区的数据丢弃,再有数据来会回复ACK并丢弃,调用read会读到EOF。对于关闭写方向会将发送缓冲区的数据发给对端并进行四次挥手

# 55.伙伴系统算法

答案

伙伴系统算法是为了解决连续内存分配的问题

将一个个页框分为大小为2^0,2^1,,,2^10个连续页框的内存块,分别放在不同的链表中,当分配一块物理内存时,假设需要x个页框,则找到最小的i满足2^i>=x并且对应的链表不为空,如果x>=2^{i-1},则将该内存块一页为而,直到不满足条件为止,将其中最小的>=x的内存块返回,其他的放回对应链表的尾部。当回还内存时,判断对应链表中是否有同属于一个内存块,如果有的并且相邻则将其合并

初始时只有x个大小为2^10的内存块,x为物理内存大小/(2^10*4KB)

由于伙伴系统算法只能处理2幂次的内存,否则会有大量浪费,因此有了slab对象,slab的内存从伙伴系统算法中获得,然后进行划分成非常多的小内存块进行管理

# 56.进程上下文切换完成流程

答案

上下文切换的时机:当进程的时间片用完会触发时钟中断或通过系统调用触发

首先会进入内核态,然后关闭自动中断,保存PCB进程控制块,进程地址空间(),页表,内核栈,寄存器等,这些信息都会保存到内核栈中,然后PCB会包含内核栈的指针,然后加载另一个进程的PCB,通过PCB找到内核栈,将其加载出来,并开启自动中断,进入用户态

# 57.文件系统

答案

一个文件由目录项(用于记录文件名,索引节点指针,目录层级关系)和索引节点(inode编号,文件大小,访问权限,数据在磁盘中的位置等等)

索引节点指向索引节点块,然后索引节点块又会指向下一级索引节点块,直到最后一级才指向数据块,这样查询效率高,易于文件增删,缺点是存储开销更大

对于磁盘空间的管理对磁盘空间进行分块,采用非连续分配算法,使用位图标识一个块是否被使用,而一个块能只能表示128MB的大小,因为需要分成N个块组,每个块组包含数据位图,多个数据块,inode位图,inode列表等等

软链接就是指通过新增inode节点,然后对应的数据块记录的是另一个文件的路径。硬链接就是通过目录项指向同一个inode节点

# 58.reactor模式

答案

reactor模式包括单reactor单线程,单reactor多线程,多reactor多线程

单reactor单线程就是io请求来的时候,分发器根据事件类型分类,如果是新连接建立则将其分发给acceptor处理,将其注册到epoll中,如果是读事件则分发给handler处理,进行read,业务处理,send

单reactor多线程就是在单线程的基础上使用多个线程处理读事件,并使用线程池进行复用

多reactor多线程就是main_reactor只负责处理新连接建立,accept取出连接后发给sub_reactor,sub_reactor将其注册到自己的epoll中,然后当事件发生时进行处理

# 59.操作系统堆和栈的底层原理

答案

堆内存的分配包括brk和mmap。brk本质上就是推brk指针,先进后出,因此会产生内存碎片,原理和栈一样,一般用于内存<128K的时候使用。mmap本质上是空闲块链表实现,每次free后会归还给操作系统

栈内存分配是通过维护esp指针(栈顶)和ebp指针(栈底),每次函数调用会先保存ebp指针,用于回溯,然后更新ebp到esp的位置,进行函数的调用

Last Updated: 2024/9/25 01:48:52