操作系统基础学习记录

JAVA学习网 2020-10-14 23:50:12

操作系统基础

1602592540954

什么是操作系统

操作系统(Operating System,简称OS)是管理计算机硬件和软件资源的程序,是计算机的基石。

操作系统本质上是一个运行在计算机上的软件程序用于管理计算机硬件和软件资源,如运行在电脑上的所有应用程序都通过操作系统来调用系统内存以及磁盘等硬件。

操作系统屏蔽了硬件层的复杂性

操作系统的内核(kernel)是操作系统的核心部分,他负责系统的进程管理,内存管理,硬件设备管理、文件系统管理以及应用程序管理。内核是连接应用程序和硬件的桥梁,决定系统的性能和稳定性。

1600091362585

系统调用(使用系统态的子功能)

根据进程访问资源的特点,我们把进程在系统上的运行分为两个级别

  • 用户态(user mode),用户态运行的进程或可以直接读取用户程序的数据
  • 系统态(kernel mode),系统态运行的进程或程序几乎可以访问计算机的任何资源,不受限制

什么是系统调用?

我们运行的程序基本都运行在用户态,但如果我们要调用操作系统提供的系统态级别的子功能怎么办呢?这时就需要用到系统调用了。也就是说再我们运行的用户程序中,凡是与系统态级别的资源有关的操作(如文件管理,进程管理,内存管理等),都必须通过系统调用的方式向操作系统提出服务请求,并由操作系统代为完成。

这些系统调用按功能大致可分为以下几类:

  • 设备管理:完成设备的请求与释放,以及设备启动等功能
  • 文件管理:完成文件的读、写、创建以及删除等功能
  • 进程管理:完成进程的创建、撤销、阻塞、唤醒以及进程间的通信等功能
  • 内存管理:完成内存的分配,回收

进程管理

进程与线程的关系以及区别

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的基本单位

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点运行中必不可少的资源(如程序计数器,一组寄存器和栈),因此切换代价比进程低,但是他可以与属于 同一个 进程的其他线程共享拥有的全部资源,管理较进程来说更繁琐

区别:进程是线程的容器,线程是进程的一个实体,而进程是程序的实体,是程序关于某数据集合上的一次运行活动, 程序一旦运行就是进程

简而言之,进程就是指正在运行的一个应用程序,程序一旦运行就是进程,进程是资源分配的最小单元;线程是进程的一个单元执行流(实体),是CPU调度分派的基本单元。

1600090270415

深入理解

进程(线程+内存+文件/网络句柄)

内存:这里的内存不是所见到的(2G/4G)等物理内存,而是逻辑内存,指内存的寻址空间,每个进程的内存相互独立

线程(栈+PC+TLS)

程序进程区别

  • 进程是一个动态的概念,程序是一个静态的概念
  • 进程是竞争计算机系统资源的基本单位,而程序不反映执行也就不会竞争计算机系统资源
  • 进程具有并行特征,而程序不反映执行所以没有并行特征
  • 不同的进程可以包含同一程序,只要该程序所对应的数据集不同。

进程有哪几种状态

  • 创建状态:进程正在被创建,尚未到就绪
  • 就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源
  • 运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数
  • 阻塞状态:进程等待某种条件,在条件满足前无法执行
  • 结束状态:进程正在从系统中消失,可能是进程正常结束或其他原因中断退出

1600087855331

进程通信的方式有哪些(7种)

每个进程都有自己独立的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程间交换数据必要要通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷贝到内核缓冲区,进程2再从内核缓冲区中把数据读走,内核提供的这种机制叫进程间通信(IPC,InterPreocess Communication)

1600175388789

  • 管道

    • 一种半双工的通信方式,数据只能单向流动,并且只能在具有亲缘关系的进程间流动(父子进程,兄弟进程),

    • 管道是一种独立的文件系统,他不是普通的文件,不属于文件系统,而是单独构成一种文件系统,只存在于内存中

    • 进程中数据的读出和写入,是一个进程向管道中写入内容,另一个管道在另一端读出,写入的内容每次都写在管道缓冲区的末尾,并每次从缓冲区头部读取数据,模型类似生活中的管道

    • 管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据,该缓冲区可以看做一个循环队列

    • 管道的局限在于只支持单向流动,必须在亲缘关系的进程间通信,没有名字,管道的缓冲区是有限的

    1600175730091

  • 命名管道:由于管道没有名字,只能在具有亲缘关系的进程间通信,为了克服这个缺点提出了命名管道,其与匿名管道不同之处在于它提供了一个路径名与之关联, 这样,即使与有名管道的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过有名管道相互通信 也是半双工通信方式,但他允许无亲缘关系的进程间通信

  • 信号:信号是Linux系统中用于进程间互相通信或操作的一种机制,信号可以在任何时候发给某一个进程,而无需知道这个进程的状态,如果该进程并未处于执行状态,则将此信号保存在内核中,直到该进程恢复执行并传递给他为止,如程序终止信号Ctrl+C可以产生该信号

    信号的生命周期及处理流程:

    1. 信号被某个进程产生,并设置此信号传递的对象(一般为对应进程的pid),然后传递给操作系统;
    2. 操作系统将信号传递给对应进程
    3. 目的进程收到信号后,暂时终止当前代码,保护上下文(临时寄存器数据,当前程序位置以及CPU状态),进入中断执行

    1600176807036

  • 消息队列:消息队列是存放在内核中的消息链表,与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或文件系统)不同的是

    1. 消息队列存放于内核中,只有内核重启或显示删除一个消息队列时才会真正删除
    2. 消息队列在某个进程往一个队列写入消息之前,不需要另一个进程在该队列上等待消息的到达,此外,消息队列允许一个或多个进程向他写入或读取数据
    3. 消息队列可以实现消息的随机查询消息也不一定以先进先出的次序读取,也可以按消息的类型读取
  • 共享内存:使得多个进程可以直接读取同一个内存空间,是最快的IPC方式,是针对其他通信机制效率低而设计的,为了在多个进程间交换信息,内核专门留出一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间,进程就可以读取这一块内存而不需要数据拷贝,大大提升效率, 由于多个进程共享一段内存,因此需要依靠某种同步机制(如信号量)来达到进程间的同步及互斥。

    1600177652960

  • 信号量: 信号量是一个计数器,可用来控制多个进程对共享资源的访问。 它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段

  • socket套接字:可用于不同设备及其间的进程通信

线程之间的通信方式

线程间由于共享进程的内存空间,因此线程中没有像进程通信中那样的数据交换通信机制,线程间的通信目的主要是用于线程同步

  • 共享变量
  • 互斥量(Mutex) : 采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。 因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
  • 信号量: 它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
  • 事件 :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较

进程的调度算法

为了确定首先执行哪个进程以及最后执行哪个进程以实现最大CPU利用率,计算机科学家定义了一些算法

  • 先到先服务(FCFS)调度算法:从就绪队列中选择一个最先进入队列的进程为之分配资源,使他立即执行到完成或发生某时间而被阻塞放弃占用CPU时再重新调度
  • 短作业优先(SJF)调用算法:从就绪队列中选出一个估计运行时间最短的进程为之分配资源
  • 时间片轮转调度算法:时间片轮转调度是一种最古老,最简单,最常用的进程调度算法,又称RR(Round robin)调度,每个进程被分配一个时间段,称他为时间片,即进程允许运行的时间
  • 优先级调度:为每个进程分配优先级,首先执行具有最高优先级的进程,依次类推。可以根据内存要求,时间要求,任何其他资源要求来确定优先级。
  • 多级反馈队列调度算法”:短作业优先调度算法仅照顾到了短进程而忽略了长进程,多级反馈队列调度即可以使高优先级的作业得到响应又能使短作业迅速完成

什么是死锁

在两个或多个并发进程中,如果每个进程拥有某个资源,而这个资源又是对方所需要的,双方都等待对方释放自己需要的资源,而都不释放,在未改变这种状态之前不能继续推进,这一组进程就产生了死锁,也就是两个或多个进程无限期的阻塞,相互等待的一种状态

产生的主要原因是:系统资源不足,进程推进顺序非法

死锁产生的四个必要条件(有 一个不成立,则不会产生死锁)

  1. 互斥条件:一个资源只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程获得的资源,在未完全使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的唤醒等待资源关系

死锁的基本处理策略和常用方法

预防死锁(资源分配问题)

  1. 资源一次性分配:破坏请求和保持条件
  2. 可剥夺资源:当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件)
  3. 资源有序分配:系统给每类资源分配一个编号,每个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

避免死锁

预防死锁的几种策略会严重损害系统性能,因此在避免死锁时需要施加较弱的限制,从而获得较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源,因而,系统在进行资源分配之前需先计算资源分配的安全性,若此次分配不会导致系统进入不安全状态,则将资源分配给进程,否则进程等待,最具代表性的避免死锁的算法是银行家算法

Windows下内存管理

操作系统的内存管理主要是做什么

操作系统的内存管理主要负责内存的分配与回收(malloc函数:申请内存,free函数:释放内存),另外地址转换即逻辑地址转换成相应的物理地址等功能也是内存管理做的事情

常见的内存管理机制

主要分为连续分配管理非连续分配管理方式,连续分配管理方式指为一个用户程序分配一个连续的内存空间,常见的如块式管理,同样的,非连续非配管理方式允许一个程序使用的内存分布在离散或不相邻的内存中,常见的页式管理和段式管理

  • 块式管理:很早时计算机操作系统的内存管理方式,将内存分为几个固定大小的块,每个块包含一个进程,当一个运行的程序需要内存的话,操作系统就分配一块,如果程序运行时只需要很小的空间的话,分配的空间中一部分就会被浪费了,这个块中未被利用的空间我们称之为碎片。
  • 页式管理:把内存分为大小相等且固定的一页一页的形式,页较小,相对于块式管理划分力度更大,提高了内存利用率,减少了碎片,页式管理通过页表对应逻辑地址和物理地址
  • 段式管理:页式管理虽然提高了内存利用率,但页式管理其中的页实际无任何实际意义。段式管理把主存分为一段段的,每一段的空间比页空s间小很多,但是,最重要的是段是有实际意义的每个段定义了一组逻辑信息, 例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址**。
  • 段页式管理:结合段式管理和页式管理的有点,现将主存分为若干段,每个段分为若干页,也就是说段页式管理机制中段与段的之间及段的内部都是离散的。

快表和多级页表

块表和分级页表时页表管理机制中两个很重要的概念,这个两个东西分别解决了页表管理中很重要的两个问题,

  1. 虚拟地址到物理地址的转换要快
  2. 解决虚拟地址空间大,页表也会很大的问题

快表

为了解决虚拟地址到物理地址的转换速度,操作系统在页表方案的基础上引入了快表来加速虚拟地址到物理地址的转换,可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中内容是页表的一部分或全部部分,作为页表的Cache,他的作用与页表类似,但提高了访问速率。由于采用页表作为地址转换,读写内存数据时CPU要访问两次主存,有了块表,有时只访问一次高速缓冲存储器,一次主存,这个样子可以加速查找。

使用快表的执行流程:

  1. 根据虚拟地址中的页号查块表
  2. 如果该页在快表中,直接从快表中获取相应的物理地址
  3. 如果该页不在快表中,那么就访问内存中的页表,再从页表中获取到物理地址,同时将页表中的该映射表添加到快表中
  4. 当快表填满时,采用一定的淘汰机制淘汰掉表中的一个页

多级页表

引入多级页表时为了避免把全部页表放在内存中占用过多的空间,特别是那些经常不需要的页表, 多级页表属于时间换空间的典型场景

总结:为了提高内存的空间性能,提出了多级页表的概念,但是提高空间性能是以浪费时间换来的,因此为了补偿时间上的损失,提出了快表的概念,无论是快表还是多级页表,都利用到了程序的局部性原理。

分页机制和分段机制的共同点和区别

共同点

  • 分页机制和分段机制都是为了提高内存利用率,减少内存碎片
  • 页和段都是离散存储的,所以两者都是离散分配内存的方式,但是,每个页和段中都是连续的

区别

  • 页的大小是固定的,由操作系统决定,而段的大小不固定,由当前运行的程序决定。
  • 分页仅仅是为了满足操作系统内存管理的需求,而段式逻辑信息的单位,程序中可以体现为代码段,数据段,能更好的满足用户的需要。
  • 段向用户提供二维地址空间;页向用户提供的是一维地址空间
  • 段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。

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

与程序接触的一般就是逻辑地址,在分段和分页内存管理机制中,要想访问物理地址,必须通过逻辑地址去访问,就像C语言程序中的指针,指针存储的数值就是逻辑地址,通过这个地址我们能够找到真正的物理地址

为什么不直接给物理地址而需要逻辑地址转换

如果没有虚拟地址,程序都是直接访问和操作物理内存,如果是这样的话会造成一些问题

  1. 用户可以访问任意内存,寻址内存的每个字节,这样很容易破坏操作系统,造成操作系统崩溃。(安全问题:系统崩溃
  2. 想要同时运行多个程序很困难,比如先运行微信时,给的内存地址是1xxxx,而QQ音乐打开时同样赋值内存空间1xxx ,那么QQ音乐对内存空间的赋值就会覆盖微信之前的赋值,造成微信崩溃。(安全问题:多进程
  3. 如何分配内存,分配多的话造成浪费并且没几个进程内存就耗尽了,分配少的话不够用(大小分配问题
  4. 如果动态分配内存,则进程拿到的内存空间是不连续的,系统要解决碎片问题。(地址空间不连续问题

总结来说,如果直接暴露物理地址会导致很多问题,比如可能对操作系统造成伤害以及给同时运行多个程序造成困难

通过虚拟地址访问的优势

  1. 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的内存缓冲区(使用离散物理地址
  2. 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常为4KB)保存到磁盘文件,数据或代码页会根据需要在物理内存与磁盘之间移动。(使用物理内存可大可小
  3. 不同进程使用的虚拟地址彼此隔离,一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。(虚拟内存物理内存彼此隔离

虚拟内存(Virtual Mmory)

虚拟内存是计算机中系统内存管理的一种技术,它使得应用程序认为它拥有连续可用的内存(一段连续完整的地址空间),而实际上,他通常被分割成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上(将内存扩展到硬盘空间),在需要时进行数据交换。目前大多数操作系统都使用了虚拟内存,如Windows的虚拟内存,Linux的交换空间。

举个简单的例子,比如我们很多时候一次性点开很多应用和网页,这时可能会出现卡屏的现象,但过了一会儿又恢复了,这里面就用到了虚拟内存,当我们点开很多应用时,内存可能被耗尽了,这时虚拟空间就将内存扩展到硬盘,使内存依然够用,但由于磁盘比内存的访问速度慢多了,所以需要等待的时间就比较长,这就是为什么等一段时间可以恢复

局部性原理

局部性原理是虚拟内存技术的基础,正式因为程序运行具有局部性原理,才可以只装入部分程序到内存就开始运行

也就是说在某个较短的时间内,程序执行局限于某一小部分,程序访问的存储空间也局限于某个区域

局部性原理表现在以下两个方面

  1. 时间局部性:如果程序中的某条指令一旦执行,不就以后该指令可能再次执行;如果某数据被访问过,不就以后该数据可能被再次访问,产生时间局部性的典型原因是由于在程序中存在大量循环操作
  2. 空间局部性:一旦程序访问了某个存储单元,不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址可能集中在一定范围内,这是因为指令通常是顺序存放,顺序执行的。

虚拟内存技术实际上就是建立了 “内存一外存”的两级存储器的结构,利用局部性原理实现髙速缓存。

虚拟存储器

基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其他部分留在外存,就可以启动程序执行,由于外存往往比内存大很多,所以我们运行的原件的内存大小实际可以比计算机系统实际的内存大的。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序,另一方面,操作系统可以将内存中暂时不同的内容换到外存上,从而腾出空间放入调入内存的信息,这样计算机好像为用户提供了一个比实际内存大的多的存储器--虚拟存储器。这也是一个时间换空间的策略。使用CPU的计算时间,页的调入调出时间,换来更大的空间。

虚拟内存的技术实现

虚拟内存的实现需要建立在离散分配的内存管理基础之上,虚拟内存的实现方式有以下三种方式

  1. 请求分页存储管理建立在分页管理基础上,为了支持虚拟存储器功能而增加了请求调页功能管理置换功能,请求分页是目前最常用的一种虚拟存储器实现方法,请求分页存储管理系统中,在作业运行之前,仅装入当前要执行的部分即可运行。加入在作业运行的过程中发现要访问的页面不在内存,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入到主存,同时操作系统也可以将暂时不用的页面置换到外存中
  2. 请求分段存储管理建立在分段存储管理之上,增加了请求调段功能分段置换功能。请求分段存储管理方式就如同请求分页存储管理方式一样,在作业运行之前,仅装入当前要执行的部分即可运行,在执行过程中,可使用请求调入中断动态装入要访问但又不在内存中的程序段,当内存空间已满时,根据置换功能调出某个段,以腾出空间装入新的段。
  3. 请求段页式存储管理

以上的几种实现方式,我们一般需要:

  1. 一定容量的内存和外存,在载入程序的时候,只需要将程序的一部分装入内存,而将其他部分留在外存,程序就可以运行了
  2. 缺页中断:如果需要执行的指令或访问的数据尚未在内存(称为缺页或缺段),则由处理器通知操作系统将相应的页面或段调入到内存,然后继续执行程序
  3. 虚拟地址空间:逻辑地址到物理地址的转换

请求分页存储管理和分页存储管理的区别:请求分页存储管理是建立在分页存储管理基础之上的,他们的根本区别在于是否将一作业的全部地址空间同时装入主存,请求分页存储管理不需要将作业的全部地址空间同时装入主存(请求调页功能和页面置换功能),基于这一点请求分页存储管理可以提供虚拟内存,而分页存储管理却不能提供

页面置换算法

虚拟内存最重要的一个概念就是页面置换算法

什么叫页面置换算法?

地址映射过程中若在页面中发现需要访问的页面不在内存中,则发生缺页中断,当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移除内存,以便为即将调入的页面让出空间,用来淘汰页面的算法叫页面置换算法

常见的页面置换算法

  1. OPT(Optimal)页面置换算法(最佳页面置换算法):最佳(Optimal,OPT)置换算法所选择的被淘汰页面是以后永不使用的,或者是最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若干页面中哪个是最长时间不使用的,因而该算法无法实现,一般用来衡量其他置换算法的方法
  2. FIFO (First In First Out) 页面置换算法(先进先出页面置换算法):总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰
  3. LRU( Least Currently Used )页面置换算法(最近最久未使用页面置换算法):LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间T,当选择一个页面淘汰时,将选择现有页面中T值最大的,即最近最久未使用的页面予以淘汰。
  4. LFU( Least Frequently Used )页面置换算法(最少使用页面置换算法):该置换算法选择在之前时期使用最少的页面作为淘汰页。

什么是缓冲区溢出

缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在了合法数据上

危害:程序崩溃或跳转并执行一段恶意代码

阅读(3587) 评论(0)