操作系统 内存相关

0 内存

cpu和内存的关系

内存覆盖

内存的覆盖是一种在程序运行时将部分程序和数据分为固定区和覆盖区的技术。这种技术的主要目的是为了解决程序较大,无法一次性装入内存导致无法运行的问题。

具体来说,内存的覆盖技术将用户空间划分为以下两个部分:

  1. 固定区: 存放程序的经常活跃的部分,这部分内容在程序运行的整个生命周期内都常驻内存中,不发生变化。

  2. 覆盖区: 将程序的其他部分按照调用关系分段,首先将即将要访问的段放入覆盖区,而其他段则放在外存中。在需要调用未在覆盖区的段之前,系统会将其调入覆盖区,替换覆盖区中原有的段,从而实现对程序和数据的动态调度。

内存覆盖技术的特点:

  • 灵活性: 允许程序只在需要时才将特定部分调入内存,而不是一次性装入整个程序。这提高了内存的利用效率。

  • 节省内存空间: 由于只有活跃部分才会常驻内存,可以在有限的内存空间中运行较大的程序。

  • 实现动态调度: 能够根据程序运行时的调用关系,动态地将程序和数据调入内存,避免了全部加载到内存的限制。

  • 需要注意更新的范围: 内存中能够更新的地方主要是覆盖区的段,因为不在覆盖区的段是常驻内存的,不会随着程序的执行而改变。

总体而言,内存的覆盖技术提供了一种灵活的方式,使得较大的程序能够在有限的内存空间中运行,并在需要时动态地调度程序和数据。

内存交换

内存交换是一种操作系统采用的技术,用于在内存紧张时进行动态的进程调度,将部分进程从内存中暂时换出,以便腾出空间供其他进程运行。同时,将一些已具备运行条件的进程从外存(磁盘等)调入内存,实现内存资源的动态调度。

特点:

  1. 解决内存紧张问题: 内存交换的主要目的是解决内存空间不足的问题。当系统中运行的进程过多,导致内存中的页面频繁发生缺页中断时,系统可以考虑进行内存交换,将部分进程换出到外存,腾出内存空间。

  2. 动态调度进程: 交换技术允许系统根据进程的运行状态和优先级,动态地在内存和外存之间进行调度。这样,即使内存中无法容纳所有进程,也可以根据需要调入最需要运行的进程。

  3. 换入和换出: 内存交换包括两个主要阶段,即换入和换出。换入是将准备运行的程序从外存移到内存,而换出是将一些处于等待状态的程序从内存移到外存。这样可以灵活地控制内存中的进程。

  4. 系统负荷降低时暂停: 内存交换通常在系统负荷较大、内存不足的情况下进行。一旦通过内存交换腾出足够的空间,系统负荷下降,缺页率明显下降,就可以考虑暂停内存交换,避免频繁地进行换入和换出,以提高系统性能。

1 虚拟内存

虚拟技术

主要有两种虚拟技术:时(时间)分复用技术和空(空间)分复用技术。

多进程与多线程:多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一小个时间片并快速切换。

虚拟内存使用了空分复用技术,它将物理内存抽象为地址空间,每个进程都有各自的地址空间。地址空间的页被映射到物理内存,地址空间的页并不需要全部在物理内存中,当使用到一个没有在物理内存的页时,执行页面置换算法,将该页置换到内存中。

why?

  1. 目的: 虚拟内存的主要目的是将有限的物理内存扩充成更大的逻辑内存空间,使得程序能够运行更大的程序或多个程序同时运行。它为每个程序提供了独立的地址空间,让每个程序都认为它在独占地使用整个内存。

  2. 地址空间和页面: 操作系统将每个程序的地址空间分割成多个块,通常称为页面。这些页面可以映射到物理内存,但不要求页面必须连续,也不要求所有页面都必须在物理内存中。

  3. 缺页中断: 当程序引用不在物理内存中的页面时,会发生缺页中断。硬件会触发必要的映射,将缺失的页面加载到物理内存中,然后重新执行引起缺页的指令。

  4. 允许部分加载: 虚拟内存允许程序只加载部分地址空间到物理内存中,而不是一次性将整个程序加载。这使得大型程序能够在有限的物理内存中运行,因为只有程序当前执行的部分需要在内存中。

分段和分页

分段(Segmentation)

好处:

  1. 产生连续的内存空间,便于程序设计和管理。
  2. 每个段可以独立调整权限,提高了系统的安全性。

问题:

  1. 外部内存碎片:由于分段机制产生的连续内存空间导致了外部内存碎片,使得分配内存的效率降低。
  2. 内存交换效率低:当需要进行内存交换时,可能需要写入或者从磁盘装载整个段,造成浪费。

分段机制将程序的虚拟地址分成若干个逻辑分段,每个分段具有不同的属性,如代码分段、数据分段、栈段、堆段等。这种机制使用段选择因子和段内偏移量构成虚拟地址。

  • 段选择因子和段内偏移量:

    • 段选择子: 存储在段寄存器中,主要包含段号,用作段表的索引。段表中保存了段的基地址、界限、特权级等信息。
    • 虚拟地址: 由段选择因子和段内偏移量组成。段内偏移量必须在0到段界限之间合法,如果是合法的,就可以通过将段基地址与段内偏移量相加得到物理内存地址。
  • 解决程序不需要关心具体物理地址的问题:

    • 分段机制通过将虚拟地址映射到物理地址,使得程序无需关心具体的物理内存地址,提高了程序的抽象性和可移植性。

优点:

段内连续

不足之处:

  1. 内存碎片问题:

    • 外部碎片: 分段机制容易导致外部碎片,不同长度的段在内存中分布可能导致未分配空间的零散浪费。
    • 解决方案: 使用分页机制可以减少外部碎片问题。
  2. 内存交换效率低:

    • 页错误开销: 当访问的段不在内存中时,会引起页错误,需要进行页面调度,导致性能开销。
    • 解决方案: 分页机制相对更适合处理内存交换,因为它可以更细粒度地调度页面。

分页(Paging)

好处:

  1. 解决了外部内存碎片问题:页与页之间是紧密排列的,避免了外部内存碎片。
  2. 更灵活的内存交换:内存分页机制以页为单位进行内存的交换,可以更加灵活地进行页面的读写。

问题:

  1. 内部内存碎片:分页机制分配内存的最小单位是一页,可能会导致内部内存碎片。

置换算法

页错误

操作系统中的页面错误(Page Fault)是指在虚拟内存系统中,当程序访问一个尚未加载到物理内存中的虚拟页面(页)时,操作系统会产生的一种异常情况。页面错误通常是由于程序试图访问虚拟内存中的某个部分,但该部分尚未被加载到物理内存中,因此操作系统需要执行以下步骤来处理页面错误:

  1. 异常触发:当程序访问虚拟内存中的某个页时,如果该页尚未加载到物理内存中,就会触发一个页面错误异常。

  2. 操作系统介入:操作系统会捕获页面错误异常,并将控制权从用户程序切换到内核态,以便处理异常。

  3. 页面加载:操作系统负责将所需的页面从磁盘或其他次级存储设备加载到物理内存中的空闲页框中。这个过程可能会导致其他页面被换出到次级存储设备以腾出空间。

  4. 页表更新:操作系统会更新虚拟内存到物理内存的映射关系,以便将虚拟地址映射到新加载到物理内存中的页面。

  5. 恢复用户程序:一旦所需的页面被加载到物理内存中,操作系统将控制权返回给用户程序,并允许其继续执行。用户程序可以重新访问所需的页面,这次访问将成功,因为页面已经加载到物理内存中。

逻辑转物理

页号、页内偏移量-->是否越界?

内存块号

物理地址

页表和快表

页表(Page Table):

  1. 定义: 页表是一种数据结构,用于存储虚拟地址空间和物理地址空间之间的映射关系。每个进程都有自己的页表,用于将其虚拟地址映射到物理地址。

  2. 工作原理: 当程序访问虚拟内存时,操作系统会使用页表查找虚拟地址对应的物理地址。页表的条目记录了虚拟页号和物理页号的映射关系。如果某个虚拟页不在内存中(发生缺页中断),操作系统会将相应的物理页加载到内存,更新页表。

  3. 缺点: 随着地址空间的增大,页表可能变得非常庞大,占用大量内存。为了解决这个问题,通常会采用多级页表结构。

快表(Translation Lookaside Buffer,TLB):

  1. 定义: 快表是一种高速缓存,用于存储页表中的部分映射关系。它位于CPU和主存之间,加速虚拟地址到物理地址的转换过程。

  2. 工作原理: 当CPU访问虚拟内存时,先在TLB中查找虚拟地址和物理地址的映射关系。如果在TLB中找到了映射关系(TLB命中),则直接使用这个映射,避免了对页表的访问。如果未命中,则需要访问页表,并将映射关系加载到TLB中。

  3. 优势: TLB的速度远高于内存访问速度,因此能够显著提高虚拟内存的访问性能。TLB的大小通常较小,因为只存储了部分页表的映射关系。

  4. TLB Miss: 当TLB未命中时,可能导致TLB Miss,需要从页表中加载映射关系。这时会引起额外的访问延迟。

有快表和每快表的区别

一般情况下:

  1. 算页号、页内偏移量:

    • 这一步主要是进行计算,并不涉及实际的内存访问。因此,这一步没有访存操作。
  2. 检查页号合法性:

    • 同样,这一步仅涉及对计算出的页号进行检查,也不涉及实际内存访问。因此,这一步没有访存操作。
  3. 查页表,找到页面存放的内存块号:

    • 在这一步,需要访问页表,将虚拟地址的页号映射到物理地址的内存块号。这一步涉及实际的内存访问,因为页表通常存储在内存中。所以,这一步有一次访存操作。
  4. 根据内存块号与页内偏移量得到物理地址:

    • 这一步涉及将内存块号与页内偏移量合并,计算出完整的物理地址。在这个过程中,通常不需要再次访问内存,因为前面已经通过页表查找得到了内存块号。所以,这一步没有额外的访存操作。
  5. 访问目标内存单元:

    • 最后一步是实际的内存访问,根据前面得到的物理地址,读取或写入目标内存单元。这一步有一次访存操作。

有快表:

先查快表再查页表,少一次

2 内存管理

malloc 原理

在执行malloc申请内存的过程中,操作系统通过两个主要的系统调用来实现动态内存分配:brkmmap

  1. brk系统调用:

    • brk系统调用用于扩展或缩小进程的数据段(heap)。
    • 当进程需要更多的堆内存时,它调用brk来增加数据段的大小。这会使数据段的末尾地址向高地址移动,为进程提供更多的可用堆空间。
    • 这个过程实际上是在调整数据段的结束地址,将其扩展到新的边界。
  2. mmap系统调用:

    • mmap系统调用用于在进程的地址空间中映射一段虚拟内存区域到某个文件或设备,或者是匿名映射。
    • malloc需要分配大块内存时,通常会使用mmap,而不是依赖于brk
    • 使用mmap可以映射一块连续的虚拟内存,而不需要连续的物理内存。这对于大型分配来说更为高效,因为mmap不会产生内存碎片。

通常,操作系统在处理malloc时会根据请求的内存大小选择使用brk还是mmap。小型分配可能会使用brk,而大型分配则可能使用mmap

内存池(复用)

为什么使用?

内存池是一种管理和分配内存的机制,通过事先分配一块固定大小的内存块(池),在需要使用内存时直接从内存池中分配,而不是通过常规的内存分配方式(如malloc)动态申请内存。内存池的使用有多个优点:

  1. 减少内存碎片: 内存池分配的内存块大小是固定的,避免了内存碎片的产生。在长时间运行的程序中,内存碎片可能导致系统性能下降。

  2. 提高分配速度: 内存池事先分配好一块固定大小的内存,当需要分配内存时,直接从内存池中获取,避免了频繁的系统调用和内存分配操作,提高了分配速度。

  3. 降低内存分配的开销: 内存分配操作本身会涉及到一些开销,例如锁的获取、内存初始化等。内存池可以通过预先分配、缓存等方式降低这些开销。(系统调用)

  4. 提高内存的重复利用: 内存池中的内存块可以被重复利用,不需要频繁地释放和重新分配内存。这对于一些长时间运行的服务或程序来说,能够提高内存的重复利用率。

  5. 控制内存的分配策略: 内存池允许程序员灵活控制内存的分配和释放策略,适应不同的应用场景。

你可能感兴趣的:(操作系统/网络/数据库,java,服务器,linux)