操作系统

前言

本篇文章主要对面试中常见的操作系统相关问题做一个总结,包括:操作系统的功能和作用、线程和进程、操作系统内存管理机制以及一些操作系统中常见的算法。

操作系统

什么是操作系统

操作系统(Operating System,简称OS),指的是直接管理计算机硬件与软件资源的程序。
操作系统的本质是一个运行在计算机上的软件程序,给用户提供一个与系统交互的界面,操作系统分为内核和外核。
内核指的是管理系统的进程、内存、设备驱动、文件和网络系统等直接操作硬件的程序,外核指的就是围绕着内核的应用程序。

操作系统的组成

操作系统一般由以下部分组成:

  • 进程管理
  • 存储管理
  • 设备管理
  • 文件管理
  • 程序接口
  • 用户界面

什么是系统调用

要说明系统调用之间,首先要说明的是系统态和用户态。
用户态指的是可以直接读取用户程序数据的进程。
系统态指的是可以直接几乎访问所有计算机的资源且不受限制的进程。
那么用户态的进程如果需要调用一些系统级别的资源。那么需要通过系统调用的方式将自己的请求提交给操作系统,并且由操作系统代为完成。
这些系统调用包括:

  • 设备管理
  • 文件管理
  • 进程控制
  • 进程通信
  • 内存管理

进程与线程

从JVM角度来说,线程是进程的更小组成部分。在Java中堆和元空间是由线程所共享的,每个线程还有自己单独的虚拟机栈、本地方法栈、程序计数器。

  • 虚拟机栈:指的是在JVM中,每个方法被执行的时候会创建一个栈帧,包括局部变量表、操作数栈、方法出口等信息,然后将栈帧压入虚拟机栈,方法执行完毕的时候再进行出栈操作。
  • 本地方法栈:指在JVM,本地方法的栈,功能与虚拟机栈类似,不过这里存放的是JAVA的本地方法(Java调用非Java代码接口)。但是也有一些JVM把本地方法栈和虚拟机栈合二为一,比如HotSpot。
  • 程序计数器:用于指示该线程目前运行到了哪一个字节码,通过字节码来实现代码的运行流程以及线程切换的时候保存现场,当执行的是本地方法的时候记录的是undefined地址。

从操作系统来说,进程是CPU资源分配的最小单位,线程则是CPU调度的最小单位。在Unix上线程是小型的进程,线程相比进程有着数据共享、切换开销小的特点。

进程有哪几种状态

进程的状态一般分为5种,具体如下:

  • 创建状态:进程正在被创建。
  • 就绪状态:进程处于准备运行状态,即进程获得了除了处理器之外的一切资源。
  • 运行状态:进程正在处理器上运行(一般同一时间一个CPU核心只有一个进程在运行)。
  • 阻塞状态:又称为等待状态,进程在等待某一事件执行完毕。
  • 结束状态:进程正在从系统中消失。

其实线程也是这样。

但是从JVM角度来说,又不是这样了。
Java中Thread.State枚举类如下(源码中还有具体注释,但是这里我为了节约空间就去掉了):

    public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }

以上状态是线程在虚拟机中的状态,而非操作系统层面的状态,由于线程运行的时间非常短,会在ready和running状态之间频繁切换,而虚拟机是把调度委托给操作系统的,所以显示线程是处于就绪还是运行状态就显得不是那么重要,所以虚拟机中的线程状态就把ready和running合成了RUNNABLE状态,用来表示该线程正在运行。
其中BLOCKED表示线程被阻塞(需要获得锁)。
WAITING状态表示,线程正在等待,就是是被调用了sleep()join()wait()方法。
TIMED_WAITING指的是有时间的等待,就是被调用了sleep(timeout)join(timeout)wait(timeout)方法。

进程间的通信方式

  1. 管道/匿名管道通信(Pipes):只能用于父子进程之间的通信。
  2. 有名管道通信(Names Pipes):拥有姓名的管道,可以在没有亲缘关系之间的进程之间通信。
  3. 信号(Signal):用于通知进程某个事件已经发生。
  4. 消息队列(Message Queuing):将要发送的消息和数据存放在内存中,相比信号和管道通信有着信息量多、可以承载有格式的字节流等优点。
  5. 信号量(Semaphores):信号量是一个计数器。
  6. 共享内存(Shared Memory):多个进程能够访问同一个块内存空间。
  7. 套接字(Sockets):用于客户端和服务器之间的相互通信。

各种通信方式的优劣

匿名管道,顾名思义,没有名字标识,匿名管道是一个特殊的文件只存在于内存中,并且随着进程的结束随之消亡。Linux中常用的ps aux|grep tomcat中的|就是一个管道,它表示把前半部分的输出作为输入传入后半部分。匿名管道只能用于父子间通信,并且是单向通信的,数据无格式且受大小限制。

命名管道的本质就是在系统中创建了一个类型为p的设备文件,没有亲缘关系的进程也可以进行通信,无论是命名管道还是匿名管道,进程的写入都缓存在内核中,另外一个进程读取的时候也是从内核中读取,所有数据都遵循先进先出的原则。

消息队列克服了管道通信是无格式的字节流的问题,消息队列实际上是保存在内核的消息链表,消息队列的格式可以是用户自定义的数据类型,所以发送方和接受方需要保持消息体的数据结构一致。消息队列的通信不是最及时的,每次数据的写入和读取都需要经过用户态和内核态之间的拷贝过程。

共享内存的实现原理就是两个进程各自将自己的一块虚拟内存映射到同一块物理内存上,它解决了消息队列需要从内核拷贝数据的问题,但是也出现了新的问题:多个进程共同竞争资源会造成数据的错乱。

为了解决共享内存的问题,信号量闪亮登场,信号量的作用就是实现进程间的同步和互斥。信号量的具体实现我们已经在操作系统课中学过了,就不再赘述了。

信号,看上去和信号量很像,但是完全不是一个东西。信号是唯一异步的通信机制,信号可以在进程和内核之间直接交互,比如调用kill,就是发送一个信号使得进程终止。进程有三种响应信号的方式:1.执行默认操作、2.捕捉信号、3.忽略信号,但是我们刚才所说的kill信号是不可以被捕捉和忽略的,只能默认操作。

socket一般用于不同主机进程的通信,Socket根据创建类型不同可以分为三种:基于TCP协议的通信、基于UDP协议的通信、本地进程间的通信。

线程间的同步方式

  1. 互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源你的权限。
  2. 信号量(Semphares):允许多个线程同时访问一个资源,但是需要控制同一个时间访问资源的最大数量。
  3. 事件(Event):Wait/Notify,使用等待或者通知操作告诉线程可以运行。

进程的调度算法

  • 先到先服务算法(FCFS):就是先入队的进程先分配资源,直至其执行完毕或者进入阻塞状态。
  • 短作业优先算法(SJF):从就绪队列中选择一个估计运行时间最短的进程分配资源。
  • 时间片轮转算法:CPU给每一个进程分配时间片,运行一段时间之后切换为下一个进程。
  • 优先级调度:为每个流程分配优先级,首先执行高优先级的进程。
  • 多级反馈队列调度算法:根据进程作业时间的长短、优先度等多个要素选择进程分配资源,是Unix操作系统采用的方式。

操作系统的内存管理机制

  • 分块管理机制:将内存划分为一个个大小相等的块,如果程序运行需要内存的话就分配给其一个块。但是如果程序只需要很小的内存的话就会造成资源浪费。
  • 分页管理机制:将内存划分为大小相等页,相比块,页的大小更小,当程序需要内存的时候就分配给其若干页。
  • 分段管理机制:根据用户程序逻辑将其划分为若干个段,段的大小是不等的。
  • 段页式管理机制:先把内存分为段,然后再把段分为页。+

快表和多级页表

分页式内存管理中对物理地址和虚拟地址做了映射,并且保留了一个页表保存了这些映射信息。
为了加快查询物理地址和虚拟地址映射的查询,操作系统在Cache中存放了一个快表,当需要进行查询的时候首先先对块表进行查询,如果页不在快表中则再去主存中访问整体的页表。
多级页表,一级页表中存放二级页表的索引,最后一级页表中存放着具体的页地址。多级页表主要是用于节约内存空间,当某一级页表不用的时候就先不加载进内存,等到需要使用的时候再加载。

虚拟地址

虚拟(逻辑)地址相对于物理地址,指的是操作系统将离散的物理地址映射为连续的虚拟地址分配给程序。具体一点的说,虚拟地址指的是内存地址寄存器中的地址,物理地址是内存单元真正的地址。

虚拟地址的作用

虚拟地址的好处在于可以防止程序直接访问物理地址进而给操作系统造成伤害。
如果直接使用物理地址,程序A使用了某一块地址,程序B后来也对这一块物理地址进行操作,那么将导致程序A出错。
是用虚拟内存可以使得多个程序同时使用内存地址而互不影响。

虚拟内存

虚拟内存为每一个进程提供了一个一致的、私有的地址空间。
虚拟内存主要有如下三个重要的能力:

  • 它把主存看作为一个存储在硬盘上的虚拟地址空间的高速缓存,并且只在主存中缓存活动区域。
  • 它为每个进程提供了一个一致的地址空间,降低了程序员对内存管理的复杂性。
  • 它保护了每个进程的地址空间不会被破坏。

虚拟存储器

虚拟存储器是指操作系统在使用程序的时候,会将活跃的一部分放入主存中,而不活跃的部分放入硬盘中,但是在程序看来自己获得了一个比实际空间大得多的存储器。
这主要运用了时间局部性和空间局部性的原理。

空间局部性和时间局部性

时间局部性:指的是当程序中的某一条指令被执行之后,不久之后该指令可能再次执行。某一个变量被使用之后,不久之后该变量可能会再次被访问。
空间局部性:程序在一段时间里访问的地址可能集中在一定的范围内。

总结起来就是,由于二八定律,程序在某个较短的时间段内,执行范围在一小部分,存储空间也在一小部分。

页面置换算法

上面说明了操作系统只将一部分页放进内存中,而大部分页放在硬盘中的方式来获取更大的可用空间。
那么当程序请求新的页面的时候,操作系统需要将一个旧的页面移出内存,然后将一个新的页面加入内存(缺页中断),如何选择页面就衍生了不同的算法:

  • FIFO页面置换算法:就是先进先出。
  • LRU页面置换算法:最长时间未使用页面算法,赋予每个页面一个标记字段,必须淘汰一个页面的时候选择最长时间未被访问的页面。
  • LFU页面置换算法:短时间内使用最少,记录最近一段时间内页面的访问次数,淘汰访问次数最少的那一个。

后记

操作系统的复习到此告一段落,接下来将复习一下数据库的知识点(因为看到设计模式问得比较少,而且我数据库比较弱)。打算先总结一下知识点,然后抽出时间来多做一些练习,这里是练习网址
本篇文章主要总结了操作系统的面试常见问题,主要分为3个部分:什么是操作系统、进程和线程、操作系统的内存管理。
主要的参考文章目录如下:
我和面试官之间关于操作系统的一场对弈!写了很久,希望对你有帮助!
java线程运行怎么有第六种状态?
五分钟彻底搞懂你一直没明白的Linux内存管理
JAVA本地方法详解,什么是JAVA本地方法?
张三同学没答好「进程间通信」,被面试官挂了…

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值