操作系统面经-面试多家公司整理
大家好,前一段时间面了一些试,这里总结一下关于操作系统的面经,我简历上写了一个操作系统相关的项目,所以面试的问题可能与平常的八股面试题等等有一些差异,更加偏向具体细节和实现。这里就面试遇到的操作系统相关问题以及我自己的想法整理一下,可以参考参考,有什么问题也还请批评指正。
这个是实际问到我的问题
自己引申出来的问题
黑色普通文字是我的“回答”或者与面试官闲聊的内容
启动
启动过程
,BIOS->MBR->Bootloader->OS,多 CPU 情况下 BSP 启动 APs,叙述每个阶段做得主要事情。上电那一刻,CS:IP = 0xf000:0xfff0,此地址上的 16 字节是个跳转地址:jmp f000:e05b(据然还真问到了具体跳转地址)
- BIOS
干了些啥事
,自检程序,将 MBR 加载到 0x7c00提问其他的固件方面的知识,BIOS,UEFI等,不太了解
- 实模式、保护模式
区别
,前者16位,地址线只用了20根,后者解开限制,前者的段寄存器里面是段基址,后者段寄存器里面是段选择子为什么有实模式,兼容?
如何进入保护模式
,构建GDT、打开A20,CR0.PG = 1
- MBR
MBR 构成
,引导程序->64字节分区表->魔数(0x55和0xAA)在哪儿
,启动盘最开始那个扇区加载到哪儿
,加载到 0x7c00主要干的事情
,根据分区表找到一个活动分区,然后加载 Bootloader如何判断是否是启动盘
,魔数 0x55 和 0xAA
- 开启分页机制(x86)
- 构建页表
- 页表地址给 CR3
- CR0.PE = 1
- BSP 启动 AP 过程(x86,中断控制器为APIC),主要通过 LAPIC 发送 INIT-SIPI-SIPI 消息... 详见 Multiprocessor Specification
OS 第一个 init 进程做了些什么
- xv6 里面打开 0 1 2 号文件
- fork 出 shell
- 然后 wait(等待孤儿进程过继给init)
提问现在的 Linux 里面干了些什么
,有简单看了看,有些复杂待研究
汇编和 C 交互的一些问题
,遵循调用约定,全局变量等在汇编时就要处理好
内存管理
寻址方式
,x86 段基址:段内偏移- 实模式下段寄存器为实际的段基址,保护模式下为段选择子
分段分页特点,为什么分页
- 分段同类型数据放在一起,分页逻辑上连续物理上分散实现离散化存储
- x86 有段寄存器,硬件上原生支持分段,其他架构硬件上似乎不支持
- x86 可以设置平坦模式,“隐藏”分段
地址转换过程
,段级转换(GDT)、页级转换(查页表)
- GDTR 中存放 GDT 的线性地址,CR3 里面存放页目录的物理地址,页表项里面存放的也是物理地址。
物理内存管理
,目前 xv6 里面简单的空闲链表法,引申到伙伴系统 Slab 分配器,不管什么地方,空间管理的方式一般就两种,链表和位图,万变不离其宗。虚拟地址空间如何布局的
堆、共享区等的管理方式,xv6 里面堆的管理方式也是链表,看侯捷老师关于 C++ 内存部分讲解,也是类似伙伴系统的思想,申请空间过大时也是 mmap 在共享区分配空间
堆空间分配算法,C++ new 出来的,能否用 free 返回
,一个 C++ 相关的问题,从堆分配的空间有个头部,头部记录了大小信息,而 new 不一定,所以最好不要这么干。缺页异常三种,写时复制、延迟分配、页面置换
写时复制的实现思想
,要点:利用页表项保留位设置为COW标志位,复制内存时(主要fork)不实际复制内存,只复制页表,并将COW=1,R/W 设置为只读,其他共享计数、回收等略,详见 xv6 写时复制实现- 延迟分配,页表项全0,只在页表中建立了映射,并未实际分配物理内存,详见 xv6 延迟分配实验
页面置换
,页表项非空,页表项 P = 0;常见页面置换算法
;页面置换交换区实现方式
,具体实现有些复杂,详见 ucore 的例子,有配套的手册讲解。
Linux kmalloc 的特点
,分配的物理内存连续
IO 管理/中断
中断、异常区别
,外、内中断异常详细分类
,据 CSAPP 中断、陷阱、故障、终止中断、异常返回的 PC 是什么
,据CSAPP,中断、陷阱下一条,异常(故障)可能返回当前 PC,终止不会返回中断过程
- 中断控制器干了什么事,见上图
如何定位的中断服务程序
,见上图- 上图 x86 的情况是硬件识别,向量中断的方式
- 还有软件识别的方式,跳到一个固定地址,然后再查询异常状态寄存器看是什么异常,再跳到特定的处理程序,一般精简指令集这么干。
开关中断的事
,一般我们说中断时保存上下文前要关中断,x86 下,关中断就是 EFLAGS 的 IF = 0系统调用过程
- 没有中断控制器这个过程,其他阶段基本相同
- 传参两种方式,寄存器,压栈(进入内核后从上下文中的栈指针寄存器获取用户态栈顶地址)
- x86下系统调用可以用中断门实现,也可以使用陷阱门实现,使用中断门进入中断自动关中断,如果使用陷阱门则不会自动关中断,这是二者唯一的区别
按下一个键到显示在屏幕上
,键盘中断 + 显卡、写显存 过程,太多略,详见@@@@DMA 过程
,不是很清楚,百度google,我也是搜的。磁盘寻址
,CHS(柱面磁头扇区)、LBA(逻辑块地址),实际上似乎不是想问这个,但面试官当时也没说清楚就下一个问题,emm??????内核态、用户态的理解
,实际上就是特权级,RPL、CPL、DPL 三者之间不同情况下的各种比较变化,特复杂。用户态到内核态栈的变化
,x86 下根据 TR 可以找到 TSS,TSS 里面有内核栈的 CS 和 ESP;RISC-V 下 sscratch 有内核上下文的地址。
文件管理
分区布局
,引导块->超级块->inode、位图、数据区写磁盘如何保证数据一致性,设计日志层
(当时某度二面,全程基本就讨论这个)inode、路径、目录、目录项、全局文件表和文件结构体、进程打开文件表和文件描述符等概念以及它们之间的关系
open close dup write read 等常见系统调用
,做了什么事情- 比如 open 的要点分配文件结构体、文件描述符。
- 这个函数只是用户接口,整个是一个是系统调用过程。
inode 相当于树形结构的索引、假如设计为哈希索引,如何设计,Cache 缓存,优劣等等讨论
硬链接、软链接区别
- 硬链接与目录项挂钩,多个目录项一个 inode 一个文件
- 软链接是个文件有自己的 inode,文件内容是路径
目录项缓存
,Linux 使用目录项缓存 dentry cache 缓存提高目录项对象的处理效率,我也只知道这个东西,待研究命令获取某个目录下的文件数量
进程
谈进程、线程、协程的理解,聊区别
,简易设计第一个进程干了些什么事
,见前切换过程
,重点换上下文、换栈为什么切换进程比切换线程慢
,除了进程“体量”大,另外切换进程要切换页表,切换页表要刷新TLB切换时机
,自己阻塞让出 CPU,时间片到了状态转换,发生中断时进程状态如何转换
,时间中断设置为就绪,其他情况在 xv6 里面没变,Linux 不了解。fork 实现
exec 实现
孤儿进程
:父进程先退出了,过继给 init 进程;僵尸进程
:子进程退出父进程没有wait僵尸进程孤儿进程的理解
,进程要退出时调用 exit,exit 会关闭文件等资源,另一部分资源是父进程调用 wait 来释放,wait 释放子进程的栈、上下文、页表、任务结构体等资源。如何解决僵尸进程
,父进程总会退出,那么在 exit 中检测是否有将是状态的子进程,如果有,将其过继给 init 进程,然后唤醒 init 让它来处理。进程间的通信
,信号、信号量、共享内存、消息队列、匿名管道、有名管道,聊简单设计调度算法
,Linux 的 CFSGo 的协程模型
,不太了解卒关于进程的命令
,如何查看进程状态等等
其他
锁的实现
,自旋锁和休眠锁自旋锁
,while 循环内存一致性
,硬件如何支持的原子操作,聊了指令 Lock 锁总线等等,CAS、Acquire/Released 等休眠锁涉及进程的休眠唤醒机制如何实现
Cache 缓存一致性
,MESI设计操作系统需要研究研究设计模式,所以设计模式
??????复杂指令集和精简指令集区别
elf 文件格式介绍,可装载段,装载地址,filesz、memsz 等
我目前大概就遇到过这些问题,其中的一些问题详细答案和图片可以关注我的公众号,里面有对操作系统的详细讲解吧。
另外今年这个形式的确比较困难,我运气还算好,提前批的时候上岸了字节,但是我自知自己情况,算法八股,网络等等其实都不太行,主要是依靠自己的操作系统项目和学习记录写的电子书《给操作系统捋条线》起死回生,面试官对这个都比较感兴趣,基本上都给了机会。感兴趣的朋友也可以去我的公众号看一看,应该有所帮助
公众号:Rand_cs