操作系统基础

  • ★★★ 进程与线程的本质区别、以及各自的使用场景。
    - ★☆☆ 进程状态。
    - ★★★ 进程调度算法的特点以及使用场景。
    - ★☆☆ 线程实现的方式。
    - ★★☆ 协程的作用。
    - ★★☆ 常见进程同步问题。
    - ★★★ 进程通信方法的特点以及使用场景。
    - ★★★ 死锁必要条件、解决死锁策略,能写出和分析死锁的代码,能说明在数据库管理系统或者 Java 中如何解决死锁。
    - ★★★ 虚拟内存的作用,分页系统实现虚拟内存原理。
    - ★★★ 页面置换算法的原理,特别是 LRU 的实现原理,最好能手写,再说明它在 Redis 等作为缓存置换算法。
    - ★★★ 比较分页与分段的区别。
    - ★★★ 分析静态链接的不足,以及动态链接的特点。

3.2 Linux

  • ★★☆ 文件系统的原理,特别是 inode 和 block。数据恢复原理。
    - ★★★ 硬链接与软链接的区别。
    - ★★☆ 能够使用常用的命令,比如 cat 文件内容查看、find 搜索文件,以及 cut、sort 等管线命令。了解 grep 和 awk 的作用。
    - ★★★ 僵尸进程与孤儿进程的区别,从 SIGCHLD 分析产生僵尸进程的原因。

操作系统面试总结 - 图1

参考JavaGuide

链接点这里跳转

其他问题

如何减少上下文切换:

无锁并发编程:多线程竞争锁时,会引起上下文切换,可以将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
CAS算法:Java的Atomic包使用CAS算法来更新数据,不需要加锁
使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程处理,造成大量线程都处于等待状态。
协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

避免死锁的几个常见方法

避免一个线程同时获取多个锁
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
尝试使用定时锁,使用lock.tryLock(timeout)替代使用内部锁机制
对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失效的情况。

系统调用

用户态和系统态
用户态运行的程序可以访问用户程序的数据
系统态运行的程序可以访问计算机的所有资源
如果用户态运行的程序需要访问系统态才可以访问的资源,进行系统态下才能使用的功能,那么就需要系统调用
系统调用按功能可以分为以下几个:文件管理、设备管理、进程管理、进程通信、内存管理

进程和线程的区别

进程是操作系统分配资源的基本单位,线程不占有资源,线程只能访问隶属于进程的资源
线程是CPU调度的最小单位
从JVM的角度看两者的区别:
Java运行时数据区有:Java堆、虚拟机栈、本地方法栈、方法区、程序计数器
这些进程都拥有,一个进程可以有多个线程,每个线程都拥有自己的程序计数器、本地方法栈、虚拟机栈,所有线程都共享Java堆、方法区
JVM角度看线程的7个状态:创建、就绪、运行、阻塞、有限期等待、无限期等待、结束。
进程的5个状态:创建、就绪、阻塞、运行、结束。

进程

进程的状态:创建状态、就绪、运行、阻塞、结束

进程间的通信方式:有名管道、匿名管道、信号、消息队列、信号量、共享内存、套接字

进程间的同步方式:信号量、互斥量、事件

进程的调度算法:先来先服务、短作业优先、时间片轮转法、多级反馈队列算法、优先级调度

死锁

死锁:两个进程相互等待对方进程占有的资源,但同时有不放弃自己占有的资源,造成无限期等待的情况,就是死锁
成为死锁的必要条件:互斥、占有并等待、非抢占、循环等待

预防死锁的方法:

一般来说破坏占用并等待、或者循环等待,这两个条件来预防死锁
1、静态分配策略
可以破坏死锁的第二个条件 占有并等待
一个进程在执行前就必须申请到他所需要的所有资源,然后才会开始运行,进程要么占有所有的资源开始运行,要么不占有资源,不会出现占有一些资源然后等待的情况

2、层次分配策略
破坏 循环等待

死锁的避免

银行家算法:当一个进程申请资源时,银行家算法先通过试探分配该线程资源,然后通过安全性分析算法判断分配后系统是否处于安全状态,如果不安全则分配作废,让该线程继续等待,如果安全则成功分配。

内存管理

操作系统的内存管理主要负责内存的分配和回收,如malloc和free;
还负责地址转换:也就是将逻辑地址转换为物理地址的功能

操作系统的内存管理机制

块式管理、页式管理、段式管理、段页式管理
分为连续分配管理方式、非连续分配管理方式,块式管理是连续的,其他是非连续的
连续分配管理方式会给用户程序分配一个连续的内存空间,非连续分配管理方式允许一个程序使用的内存分布在离散或者不相邻的内存中,常见页式管理和段式管理

块式管理:将内存划分为一块一块的区域,当程序运行需要内存时,操作系统就分配给他一块,当程序只需要很小的内存时,就会浪费一部分空间,浪费的区域我们称为碎片

页式管理:将内存划分为大小相等的一页一页的区域,相比于块的大小更小,划分力度更大,提高了内存使用效率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。

段式管理:页式管理划分的页式没有实际意义的,段式管理把划分为一段一段的,是有实际意义的,每个段定义了一种逻辑信息,比如,程序段、数据段、栈段。段式管理通过段表对应逻辑地址和物理地址。

段页式管理: 结合了页式管理和段式管理的优点,先把内存划分为若干段,每个段又分为若干页。段与段之间,段的内部都是离散的。

总结:页是物理单位,段是逻辑单位。分页可以提高内存使用效率,分段可以满足用户的需求。

分页机制和分段机制的区别?

相同点:
1.都是为了提高内存的使用效率
2.都是离散化存储的,离散分配内存的方式,但是页和段的内部是连续的内存。
不同点:
1.页的大小是固定的,段的大小不固定
2.分页是为了满足操作系统更有效管理内存的需求,分段是为了满足用户需要,段可以存储逻辑信息,一段代码,一段数据等等。

快表和多级页表

快表相当于是高速缓冲存储器(cache),加速虚拟地址到物理地址的转换,作用和页表是相似的,数据只有页表的部分数据,作为页表的缓存。
如果访问快表的话,只需要访问一次cache和一次主存就可以读取内存的数据。如果是访问页表,则需要两次访问主存的操作。快表提高了访问速率。

使用快表后地址转换的流程:
1.先从快表中查询页号,如果存在则从快表拿到物理地址
2.如果不存在则查询页表,从内存中的页表中得到物理地址,并将其添加到快表中
3.快表满了后,通过淘汰算法淘汰掉一个页

虚拟地址(逻辑地址)和物理地址

我们编程用到的地址一般都是逻辑地址,比如c语言中的指针中存储的地址是逻辑地址,是由操作系统决定的。物理地址是指真实物理内存中的地址,物理地址是内存单元真正的地址。

CPU寻址?为什么需要虚拟地址空间?

CPU使用虚拟寻址的方式,将虚拟地址翻译成真实的物理地址,才能访问到真实的物理内存。
完成虚拟寻址的是CPU中的一个成为内存管理单元(MMU)的硬件
为什么需要有虚拟地址空间?
在没有虚拟地址空间之前,程序都是直接操作和访问的真实的物理地址。

  • 这会给操作系统带来崩溃的风险
  • 想要运行多个程序特别困难, 因为不知道哪个程序会操作哪个内存地址。

使用虚拟地址的优势:

  • 使用一段相邻的虚拟地址空间来访问物理内存中不相邻的大内存缓冲区
  • 程序可以使用一系列虚拟地址来访问大于实际物理内存的内存缓冲区。也就是虚拟内存的概念。
  • 不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改另一个进程正在使用的物理内存。

    什么是虚拟内存?

    虚拟内存可以让程序拥有超过物理内存大小的可用内存空间。
    虚拟内存为程序提高了一个一致的、私有的地址空间,他让每个进程产生了自己在独享内存的错觉。(每个进程拥有一片连续的完整的内存空间)
    虚拟内存的意义是定义了一个连续的虚拟地址空间,并且把内存扩展到硬盘空间。

局部性原理

程序在执行的时候往往呈现局部性规律,也就是说在某个较短的时间段内,程序执行局限于一小部分,程序访问的存储空间也局限于某个区域。
局部性原理主要体现在以下两个方面
1.时间局部性
如果一条指令一旦执行,则不久该指令可能还会被执行;如果数据被访问过,则不久该数据还会被访问。
产生时间局部性的原因是程序中存在着大量循环语句。
2.空间局部性
一旦程序访问了某个存储单元,在不久后,其附近的存储单元也很有可能被访问。即程序在一段时间内所访问的地址,可能集中在一定范围之内。

虚拟内存的技术实现

一定容量的内存和外存,在载入程序的时候,只需要将程序的一部分载入内存,其他部分留在外存,程序就可以开始运行,
缺页中断:如果执行的指令或数据未在内存(缺页或缺段),那么由CPU通知操作系统将相应的页面调入内存,然后执行该程序
虚拟地址空间:逻辑地址到物理地址的转换。

页面置换算法

LRU
OPT
FIFO