0


八股面试大总结②——Linux系统

2.1 进程线程区别

  • 进程是资源分配的基本单位,线程是资源调度的基本单位
  • 每个进程有自己的私有地址空间、私有栈、堆,上下文切换需要切换虚拟地址空间
  • 线程之间公有一个地址空间、公有堆,但是栈和程序计数器是私有的,用来保存线程的执行历史和执行状态,上下文切换只需要切换少量寄存器

2.2 进程间通信方式

  • 匿名管道: - 只能在父子进程中使用- pipe函数创建,在内核中创建一个环形队列作为缓冲区,兵返回两个文件描述符,一个用于读(fd[0]),一个用于写(fd[1])- 一个进程写数据就是写到内核缓冲区中,另一个进程可以从缓冲区中读取数据- 单向的,数据只能在一个方向上流动。如果需要双向通信必须创建两个管道
  • 命名管道: - 可以使用mkfifo函数创建,在文件系统中有一个对应的文件名可以通过文件名访问- 使用文件操作函数read、write来读写命名管道- 支持双向通信和跨网络通信,多个进程可以连接到同一个命名管道进行读写操作
  • 消息队列: - 独立于进程存在,当进程向消息队列发送消息时,会被存储在内核空间,直到其他进程从队列中读取- 允许异步通信,克服了管道缓冲区大小受限、只能承载无格式字节流的问题
  • 共享内存: - 允许多个进程访问同一块内存区域,从而实现进程间数据共享- 是最快的通信方式,避免了数据拷贝,但需要解决并发访问和同步的问题,同步机制包括互斥锁、信号量和事件等- 互斥锁要在全局命名空间中创建,这样能让多个不同的进程能够识别并访问同一个互斥锁
  • 信号量: - 用于多进程对共享资源访问的同步机制,P操作代表申请资源,V操作代表释放资源- 信号量也要使用全局命名空间
  • 套接字: - 网络通信接口,支持TCP/UDP等多种协议,一个进程作为服务器(监听套接字),另一个进程作为客户端(连接套接字)
  • 信号: - 允许一个进程向另一个进程发送信号;信号可以由多种原因产生,包括用户操作、硬件异常以及程序显式请求等- 是一种异步通信方式- 通过kill函数或raise函数发送信号(kill是发给另一个进程,raise是发给自己信号),当信号发送到进程时,会通过中断并调用相应的信号处理函数,可以使用signal函数处理

2.3 线程间通信方式

  • 共享内存
  • 消息队列:可以实现线程间解耦合,使得线程之间不需要直接访问对方的内存空间
  • 同步对象:如信号量、条件变量等
  • 原子操作
  • future和promise:允许一个线程向另一个线程传递异步计算的结果 - promise用于设置一个可由future检索的结果,future提供了一种阻塞或非阻塞的方式获取结果

2.4 锁和死锁

  • 两个基础锁:互斥锁和自旋锁 - 互斥锁:用于实现互斥访问共享资源,任何时刻只有一个线程可以持有互斥锁- 自旋锁:基于忙等待的锁,线程通过不断轮询尝试获取锁直到锁被释放
  • 其他锁都是基于以上两个锁: - 读写锁:分为共享和排他,允许多个线程同时读共享资源,只允许一个线程进行写操作- 悲观锁:多线程同时修改共享资源的概率比较高,所以访问共享资源时就要上锁- 乐观锁:多线程访问共享资源时不上锁,如果出现同时修改资源的情况就放弃本次操作
  • 死锁:多个进程在运行时因争夺资源而造成的一种僵局,占有自身资源并请求对方资源 - 产生死锁的四个必要条件: - 一段时间某资源仅能被一个进程占用- 对已获得的资源保持不放- 获得资源后不可被剥夺- 存在环形链- 解决方式: - 预防死锁:一次性分配所有资源、如果一个进程有部分资源得不到那么其他资源也不分配给他、如果一个进程获得了部分资源但得不到其他资源就会主动释放获得的资源、给资源设定编号每个进程按编号递增顺序请求资源- 避免死锁:银行家算法- 检测死锁:建立资源分配图、判断是否有环路- 解除死锁:进程回滚、剥夺资源、终止进程- 鸵鸟策略:死锁发生的概率很低的时候假装没发生死锁,因为要解决死锁的代价很高

2.5 Linux的内核设计理念

  • 多任务:多个任务同时执行。单核CPU时间轮询方式并发执行,多核CPU多个任务同时在不同CPU上并行执行
  • 对称多处理SMP:每个CPU的地位是相等的,对资源的使用权限也是相同的,多个CPU共享同一内存
  • 可执行文件链接格式ELF:Linux操作系统中可执行文件的存储格式
  • 宏内核: Linux的内核是一个完整的可执行程序,且拥有最高的权限

2.6 虚拟内存的作用和实现方式

  • 虚拟地址可以把进程所使用的地址隔离开,进程间互不干涉
  • 操作系统引入虚拟内存,进程持有的虚拟地址通过MMU的映射关系转换成物理地址,物理地址访问内存
  • 操作系统管理虚拟地址和物理地址的关系的方法:内存分段和分页

2.7 分段、分页、段页式

  • 分段: - 程序由代码段、数据段、栈段、堆段4个部分组成,将不同的段用分段的形式分离开- 分段机制下,虚拟地址由段选择因子和段内偏移量组成。段选择因子里的段号用作段表的索引,段表保存了段的基地址、段的界限和特权等级等;段内偏移量位于0和段界限之间- 段基地址+段内偏移量 = 物理地址
  • 分页: - 把整个虚拟内存和物理内存切成一段段固定尺寸的大小,称为一页,每页4KB- 页表存储在内存里,通过MMU将虚拟内存地址转换为物理地址,如果进程访问虚拟地址在页表中查不到会产生缺页异常- 分页机制下,虚拟地址分为页号和页内偏移。页号作为页表的索引,页表包含物理页每页所在的物理内存的基地址,基地址+页内偏移 = 物理地址- 一开始是单页表,为了减小内存占用,产生多级页表,如果某个一级页表没有被用到也就不需要再内存中创建对应的二级页表了;为了降低时间开销,引入页表缓存,也叫TLB,利用程序的局部性原理,把最常访问的几个页表存储到缓存中
  • 段页式: - 先将程序划分为多个段,再把每个段划分为多个页,地址结构由段号、段内页号和页内偏移组成,每个程序一张段表,每个段有一张页表,段表中的地址是页表的起始地址,页表中的地址是某页的物理页号- 要得到物理地址需要经过三次内存访问: - 访问段表,得到页表起始地址- 访问页表,得到物理页号- 将物理页号与页内偏移组合,得到物理地址

2.8 Linux内存管理

  • 程序所使用的地址称为逻辑地址,通过段式内存管理映射成线性地址,也叫虚拟地址,再由页式内存管理映射成物理地址

2.9 用户态和内核态的区别

  • 主要是为了提高系统的稳定性、安全性和性能,在这两种状态下,处理器对资源的访问权限不同
  • 用户态只能访问受限资源,无法修改硬件配置等,主要是防止用户程序对系统关键资源的非法访问
  • 内核态可以访问系统的所有资源,包括资源分配、进程调度等核心功能
  • 用户态通过系统调用、异常或中断进入内核态,而内核态设置程序状态字返回用户态

2.10 中断

  • 中断指CPU暂停正在执行的程序,保存现有程序的上下文然后去执行相应的处理程序,处理完再返回中断处继续执行原来的程序
  • 中断分为软中断、硬中断(外部中断)、内部中断 - 软中断是由程序的指令触发的中断,比如说系统调用,是不能被屏蔽的- 硬中断是由CPU外部引起的,比如IO中断、时钟中断等,可以屏蔽- 内部中断是由CPU或其他硬件生成的信号,例如浮点运算溢出、除零错误等
  • 中断保存的东西存放在栈中
  • 中断处理包括中断请求、中断判优、中断响应(从多个CPU中断请求中选择一个优先级最高的)、中断服务和中断返回五个阶段

2.11 静态链接、动态链接,静态链接库、动态链接库

  • 静态链接:编译链接时将代码拷贝到调用出 - 代码运行速度快,但是会浪费空间
  • 动态链接:代码在需要的时候才会加载到内存,多个程序调用一个代码时可以共享内存 - 运行时加载,速度慢
  • 静态链接库:在程序编译时,将库直接链接到最终的可执行文件中 - 一旦可执行文件被创建就包含了库的所有数据不再需要库文件支持即可独立运行,但生成的可执行文件较大,库中数据被多次复制,且库更新需要重新编译
  • 动态链接库:在程序运行时,库的数据被加载到内存中,而不是链接到可执行文件中 - 程序更加模块化和可移植,但会增加程序的运行时间

2.12 为什么线程的上下文切换比进程快

  • 因为每个进程都有自己的虚拟地址空间,每个进程都有自己的页表,进程切换时页表也要切换,导致TLB失效,缓存命中率降低,查找页表也耗时

2.13 进程状态切换的五种状态

  • 创建状态、就绪状态、运行状态、阻塞状态、终止状态

2.13 孤⼉进程、僵⼫进程、守护进程

  • 一般来说,子进程由父进程创建,但是父子进程的退出是无顺序的
  • 孤儿进程:父进程先退出,子进程还没有退出,交给init进程
  • 僵尸进程:子进程终止,父进程没有调用wait函数获取子进程状态,子进程残留的状态信息变成僵尸进程
  • 守护进程:运行在后台不与任何终端关联的进程,通常在系统启动时就在运行,周期性执行任务

2.14 进程调度算法、页面置换算法、动态分区分配算法、磁盘调度算法

标签: linux 面试

本文转载自: https://blog.csdn.net/qq_51148151/article/details/141202365
版权归原作者 Mr. Lee~! 所有, 如有侵权,请联系我们删除。

“八股面试大总结②——Linux系统”的评论:

还没有评论