• 操作系统-内存管理、进程线程


    目录

    (1)内存管理

     1.操作系统是如何管理虚拟地址与物理地址之间的关系?内存分段/分页

     2. 分页和分段有什区别?

     3. 什么是交换空间?

     4.什么是虚拟内存?有什么作用?

    (2)进程管理

    1.什么是进程

    2.并行与并发

    3.进程的状态及变化

    ​4.进程的特征

    6.进程控制块

    7.进程和程序的区别?

    8.什么是线程?

    10.线程与进程的比较


    (1)内存管理

    1.操作系统是如何管理虚拟地址与物理地址之间的关系?内存分段/分页

    • 分段是为了满足程序员在编写代码的时候的一些逻辑需求(比如数据共享,数据保护,动态链接等)。内存分段是根据程序的逻辑角度,分成了栈段、堆段、数据段、代码段等,这样可以分离出不同属性的段,同时是一块连续的空间。但是每个段的大小都不是统一的,这就会导致外部内存碎片和内存交换效率低的问题。
    • 于是,就出现了内存分页,分页是为了提高内存利用率,把虚拟空间和物理空间分成大小固定的页,如在 Linux 系统中,每一页的大小为 4KB。由于分了页后,就不会产生细小的内存碎片,解决了内存分段的外部内存碎片问题。同时在内存交换的时候,写入硬盘也就一个页或几个页,这就大大提高了内存交换的效率。

    分段:

    程序是由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段是有不同的属性的,所以就用分段(Segmentation)的形式把这些段分离出来。

    分段内存管理当中,地址是二维的,一维是段号,二维是段内地址;其中每个段的长度是不一样的,而且每个段内部都是从0开始编址的。由于分段管理中,每个段内部是连续内存分配,但是段和段之间是离散分配的,因此也存在一个逻辑地址到物理地址的映射关系,相应的就是段表机制。

    分段的好处就是能产生连续的内存空间,但是会出现「外部内存碎片和内存交换的空间太大」的问题。

    • 第一个就是内存碎片的问题。

    内存分段管理可以做到段根据实际需求分配内存,所以有多少需求就分配多大的段,所以不会出现内部内存碎片。但是由于每个段的长度不固定,所以多个段未必能恰好使用所有的内存空间,会产生了多个不连续的小物理内存,导致新的程序无法被装载,所以会出现外部内存碎片的问题。

    解决「外部内存碎片」的问题就是内存交换

    • 第二个就是内存交换的效率低的问题。

    外部内存碎片是很容易产生的,产生了外部内存碎片,那不得不重新 Swap 内存区域,这个过程会产生性能瓶颈。因为硬盘的访问速度要比内存慢太多了,每一次内存交换,我们都需要把一大段连续的内存数据写到硬盘上。所以,如果内存交换的时候,交换的是一个占内存空间很大的程序,这样整个机器都会显得卡顿。

    为了解决内存分段的「外部内存碎片和内存交换效率低」的问题,就出现了内存分页。

     分页:

    分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间,我们叫Page)。在 Linux 下,每一页的大小为 4KB。虚拟地址与物理地址之间通过页表来映射,以实现从页号到物理块号的映射。

    总结一下,对于一个内存地址转换,其实就是这样三个步骤:

    • 把虚拟内存地址,切分成页号和偏移量;
    • 根据页号,从页表里面,查询对应的物理页号;
    • 直接拿物理页号,加上前面的偏移量,就得到了物理内存地址。

     访问分页系统中内存数据需要两次的内存访问 (一次是从内存中访问页表,从中找到指定的物理块号,加上页内偏移得到实际物理地址;第二次就是根据第一次得到的物理地址访问内存取出数据)。

    • 分页是怎么解决分段的「外部内存碎片和内存交换效率低」的问题?

    内存分页由于内存空间都是预先划分好的,也就不会像内存分段一样,在段与段之间会产生间隙非常小的内存,这正是分段会产生外部内存碎片的原因。而采用了分页,页与页之间是紧密排列的,所以不会有外部碎片。

    但是,因为内存分页机制分配内存的最小单位是一页,即使程序不足一页大小,我们最少只能分配一个页,所以页内会出现内存浪费,所以针对内存分页机制会有内部内存碎片的现象。

    段页式内存管理:

    内存分段和内存分页并不是对立的,它们是可以组合起来在同一个系统中使用的,那么组合起来后,通常称为段页式内存管理

    • 先将程序划分为多个有逻辑意义的段,也就是前面提到的分段机制;
    • 接着再把每个段划分为多个页,也就是对分段划分出来的连续空间,再划分固定大小的页;

    这样,地址结构就由段号、段内页号和页内位移三部分组成。

    用于段页式地址变换的数据结构是每一个程序一张段表,每个段又建立一张页表,段表中的地址是页表的起始地址,而页表中的地址则为某页的物理页号,如图所示:

    段页式地址变换中要得到物理地址须经过三次内存访问:

    • 第一次访问段表,得到页表起始地址;
    • 第二次访问页表,得到物理页号;
    • 第三次将物理页号与页内位移组合,得到物理地址。

    Linux 内存主要采用的是页式内存管理,但同时也不可避免地涉及了段机制

    Linux 系统中的每个段都是从 0 地址开始的整个 4GB 虚拟空间(32 位环境下),也就是所有的段的起始地址都是一样的。这意味着,Linux 系统中的代码,包括操作系统本身的代码和应用程序代码,所面对的地址空间都是线性地址空间(虚拟地址),这种做法相当于屏蔽了处理器中的逻辑地址概念,段只被用于访问控制和内存保护。

    2. 分页和分段有什区别?

    1. 分页对程序员是透明的,但是分段需要程序员显式划分每个段。
    2. 分页的地址空间是一维地址空间,分段是二维的。
    3. 页的大小不可变,段的大小可以动态改变。
    4. 分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。

    3. 什么是交换空间?

    每个进程都有自己的虚拟空间,而物理内存只有一个,所以当启用了大量的进程,物理内存必然会很紧张,于是操作系统会通过内存交换技术,把不常使用的内存暂时存放到硬盘(换出),在需要的时候再装载回物理内存(换入)。

    操作系统把物理内存(physical RAM)分成一块一块的小内存,每一块内存被称为页(page)。当内存资源不足时,Linux把某些页的内容转移至硬盘上的一块空间上,以释放内存空间。硬盘上的那块空间叫做交换空间(swap space),而这一过程被称为交换(swapping)。物理内存和交换空间的总容量就是虚拟内存的可用容量。

    用途:

    物理内存不足时一些不常用的页可以被交换出去,腾给系统。

    程序启动时很多内存页被用来初始化,之后便不再需要,可以交换出去。

    4.什么是虚拟内存?有什么作用?

    虚拟内存就是说,让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。虚拟内存使用部分加载的技术,让一个进程或者资源的某些页面加载进内存,从而能够加载更多的进程,甚至能加载比内存大的进程,这样看起来好像内存变大了,这部分内存其实包含了磁盘或者硬盘,并且就叫做虚拟内存。

    • 第一,虚拟内存可以使得进程对运行内存超过物理内存大小。因为程序运行符合局部性原理,CPU 访问内存会有很明显的重复访问的倾向性,对于那些没有被经常使用到的内存,我们可以把它换出到物理内存之外,比如硬盘上的 swap 区域。
    • 第二,由于每个进程都有自己的页表,所以每个进程的虚拟内存空间就是相互独立的。进程也没有办法访问其他进程的页表,所以这些页表是私有的,这就解决了多进程之间地址冲突的问题。
    • 第三,页表里的页表项中除了物理地址之外,还有一些标记属性的比特,比如控制一个页的读写权限,标记该页是否存在等。在内存访问方面,操作系统提供了更好的安全性。

    5.内存满了会发生什么?

    内存分配过程:

    应用程序申请内存时实际上申请的是虚拟内存,此时并不会分配物理内存;读写后如果发现这个虚拟内存没有映射到物理内存,CPU就会产生缺页中断,进程会从用户态换到核心态,将缺页中断交给内核处理,分配物理内存。

    缺页中断函数会先看看是否有空闲的物理内存,如果有就直接分配物理内存,并建立虚拟内存与物理内存之间的映射关系;如果没有空闲的物理内存,那么内核就会开始进行回收内存工作,回收的方式主要有直接内存回收和后台内存回收两种,

    回收后还不满足此次申请,那么就会触发OOM机制,OOM Killer机制会根据算法选择一个占用物理内存较高的进程,然后将其杀死,以便释放内存资源,如果物理内存依然不足,OOM Killer 会继续杀死占用物理内存较高的进程,直到释放足够的内存位置。

    (2)进程管理

    1.什么是进程

    定义:进程就是一段程序的执行过程。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

    2.并行与并发

    并行是指两个或者多个事件在同一时刻发生,而并发是指两个或多个事件在同一时间间隔发生。

    并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。

    3.进程的状态及变化

    进程一共有5种状态,分别是创建、就绪、运行(执行)、终止、阻塞。

    引起进程状态转换的具体原因如下:

    运行态→阻塞态:等待使用资源;如等待外设传输;等待人工干预。

    阻塞态→就绪态:资源得到满足;如外设传输结束;人工干预完成。

    运行态→就绪态:时间片被用完;出现有更高优先权进程。

    就绪态→运行态:CPU 空闲时选择一个就绪进程。

      

     ​4.进程的特征

    动态性:进程是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
    并发性:任何进程都可以同其他进程一起并发执行
    独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
    异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。


    结构特征:进程由程序、数据和进程控制块三部分组成;
    多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果; 但是执行过程中,程序不能发生改变。

    6.进程控制块

    PCB 是进程存在的唯一标识,这意味着一个进程的存在,必然会有一个 PCB,如果进程消失了,那么 PCB 也会随之消失。

    PCB 具体包含信息:

    ①进程描述信息:

    • 进程标识符:标识各个进程,每个进程都有一个并且唯一的标识符;
    • 用户标识符:进程归属的用户,用户标识符主要为共享和保护服务;

    ②进程控制和管理信息:

    • 进程当前状态,如 new、ready、running、waiting 或 blocked 等;
    • 进程优先级:进程抢占 CPU 时的优先级;

    ③资源分配清单:

    • 有关内存地址空间或虚拟地址空间的信息,所打开文件的列表和所使用的 I/O 设备信息。

    ④CPU 相关信息:

    • CPU 中各个寄存器的值,当进程被切换时,CPU 的状态信息都会被保存在相应的 PCB 中,以便进程重新执行时,能从断点处继续执行。

    每个 PCB 是如何组织的呢?

    通常是通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。比如:

    • 将所有处于就绪状态的进程链在一起,称为就绪队列
    • 把所有因等待某事件而处于等待状态的进程链在一起就组成各种阻塞队列
    • 另外,对于运行队列在单核 CPU 系统中则只有一个运行指针了,因为单核 CPU 在某个时间,只能运行一个程序。

    7.进程和程序的区别?

    1. 程序是指令和数据的有序集合,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个 动态的概念。
    2. 程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。
    3. 同一程序同时运行于若干个数据集合上,它将属于若干个不同的进程,也就是说同一程序可以对应多个进 程。
    4. 在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单元都是进程。
       

    8.什么是线程?

    线程是进程当中的一条执行流程。线程之间可以并发运行且共享相同的地址空间。

    同一个进程内多个线程之间可以共享代码段、数据段、打开的文件等资源,但每个线程各自都有一套独立的寄存器和栈,这样可以确保线程的控制流是相对独立的。

    9.线程的优缺点?

    线程的优点:

    • 一个进程中可以同时存在多个线程;
    • 各个线程之间可以并发执行;
    • 各个线程之间可以共享地址空间和文件等资源;

    线程的缺点:

    • 当进程中的一个线程崩溃时,会导致其所属进程的所有线程崩溃(这里是针对 C/C++ 语言,Java语言中的线程奔溃不会造成进程崩溃,)

    10.线程与进程的比较

    线程与进程的比较如下:

    • 调度:进程是资源管理的基本单位,线程是系统调度的基本单位。
    • 切换:线程上下文切换比进程上下文切换要快得多。
    • 进程包含线程,每个进程至少包含一个线程。
    • 系统开销:线程能减少并发执行的时间和空间开销。 创建或撤销进程时,系统都要为之分配或回收系统资源,如内存空间,I/O设备等,OS所付出的开销显著大于在创建或撤销线程时的开销,进程切换的开销也远大于线程切换的开销。

    对于,线程相比进程能减少开销,体现在:

    • 线程的创建时间比进程快,因为进程在创建的过程中,还需要资源管理信息,比如内存管理信息、文件管理信息,而线程在创建的过程中,不会涉及这些资源管理信息,而是共享它们;
    • 线程的终止时间比进程快,因为线程释放的资源相比进程少很多;
    • 同一个进程内的线程切换比进程切换快,因为线程具有相同的地址空间(虚拟内存共享),这意味着同一个进程的线程都具有同一个页表,那么在切换的时候不需要切换页表。而对于进程之间的切换,切换的时候要把页表给切换掉,而页表的切换过程开销是比较大的;
    • 由于同一进程的各线程间共享内存和文件资源,那么在线程之间数据传递的时候,就不需要经过内核了,这就使得线程之间的数据交互效率更高了;

    所以,不管是时间效率,还是空间效率线程比进程都要高

  • 相关阅读:
    Java Spring Cloud XVIII 之 Kafka I
    React 使用echarts绘制个性滚动柱状图
    基于SpringBoot+RabbitMQ+Redis开发的秒杀系统(异步下单、热点数据缓存、解决超卖)
    LeetCode刷题笔记之 94. 二叉树的中序遍历(史上最全的二叉树遍历的算法-Java)
    Windows下libmodbus 支持upd库的编译与Qt里的调用
    第三话、程序员第一家公司有多重要
    Ubuntu 20.04.4LTS 系统无法启动修复
    Linux之进程替换
    Git Commit规范指北
    矩阵系统能做什么
  • 原文地址:https://blog.csdn.net/weixin_45780538/article/details/126196173