清晰讲解Linux内核,连续内存分配与非连续内存分配(图例解析)

Posted 贺二公子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了清晰讲解Linux内核,连续内存分配与非连续内存分配(图例解析)相关的知识,希望对你有一定的参考价值。

原文地址:https://blog.csdn.net/csbmww/article/details/124148373


文章目录

一. 连续内存分配

1.计算机体系结构和内存层次

存储的层次结构

  1. 首先是cpu中的两级缓存,如果在读写指令时,缓存中有数据了,那么这时候速度是最快的。
  2. 如果没在缓存中,则必须去内存里读。(前两者是在硬件上)
  3. 如果内存里还是没有,则需要通过操作系统的控制去外存里读
  4. 这三者之间的访问速度差异很大

内存管理的需求

  1. 抽象:把线性的物理地址编号转换成抽象的逻辑地址空间
  2. 保护:每个进程只能访问自己的空间,尽管在内存中他们是相邻存放的
  3. 共享:任何保护机制都具有灵活性,以允许多个进程访问内存同一部分
  4. 虚拟化:实现更大的地址空间(使逻辑地址空间大于物理地址空间)


内存管理方式

  1. 重定位:在地址访问的时候,每个地址是用段地址加一个偏移来表示的,可以通过重定位改段地址来实现程序的运行。
  2. 分段:在重定位时,一个进程分配的空间是连续的存储空间,可以采用分段解决这种连续存储空间的问题,对于应用程序来说,至少可以分成代码段、数据段、堆栈段。
  3. 分页:在分段中,仍然需要一段内容是连续的,分页就是把内存分成最基本的单位(非一个字节,粒度太细)
  4. 虚拟存储:在分页的基础上,希望逻辑的地址空间大于物理地址空间。

2.地址空间和地址生成

地址空间定义

  1. 物理地址空间:在机器总线上看到的地址就是物理地址,所有物理地址构成的空间就是物理地址空间。地址总线指的就是物理地址总线的条数。这种地址是唯一的,但是对于应用程序来说,不可能每次运行之前都知道该物理地址,这样就需要逻辑地址空间了。
  2. 逻辑地址空间:cpu运行时,进程能使用的地址空间。

逻辑地址的生成

源代码–>编译成编译指令(汇编码)–>汇编成二进制代码(机器认识的指令)–>链接到函数库–>程序加载(重定位)


地址生成过程

  • CPU执行某条指令时,算术逻辑单元(arithmetic and logic unit, ALU)发出请求:逻辑地址;
  • CPU中MMU表查找逻辑地址对应的物理地址,如果没有去内存中找;
  • 找到后,CPU控制器给主存发出请求:需要某个物理地址上的内容。
  • 主存把内存的内容通过总线传给CPU,CPU执行。

操作系统起了什么作用?

  • 操作系统在四步之前,要把映射建立好;
  • 确保访问的地址空间是合法、安全的。


地址检查过程

  1. 首先是逻辑地址经过cpu判断指令要访问的段长度是否大于段长度寄存器中记录的长度,如果是的话,则报异常
  2. 段长度+段基址生成实际的物理地址空间
  3. 操作系统可以通过设置起始地址和最大逻辑地址空间来影响这整个过程。

3.连续内存分配

连续内存分配和内存碎片

连续内存分配是指给进程分配一块不小于指定大小的连续的物理内存区域。

内存碎片是指空闲内存不能被利用的,内存碎片又分为外部碎片和内部碎片,外部碎片指的是分配单元之间未 被使用的内存,内部碎片指的是分配单元内部未被使用内存。

动态分区分配

当程序被加载执行时,分配一个进程指定大小可变的分区(块、内存块)。

动态分区分配策略:

  • 最先匹配:最先找到哪个满足条件的空闲分区就把进程分区放进去(一般性能最好)
  • 最佳匹配:找最佳的空闲分区 ,使得空闲分区大小和进程分区大小接近
  • 最差匹配:每次用的空闲分区都是最大的。

3种匹配算法的比较



4.碎片整理

碎片整理是指调整进程占用的分区位置来减少或避免分区碎片。

  • 紧凑(压缩)
    通过移动分配给进程的内存分区,以合并外部碎片。这就需要进程都是可以动态重定位的,而且一般只搬动正处于等待进程状态。
  • 分区对换
    通过抢占并回收处于等待状态进程的分区,以增大可用内存空间。同时,将等待进程的数据存到外存里面。这里的问题主要是考虑交换哪些进程。

5.伙伴系统

伙伴系统把整个内存块的大小约定为必须是2的幂。

伙伴系统的实现

分配过程


释放过程和合并条件

在释放分区的过程中,把释放的块放入空闲快数组,合并满足合并条件的空闲块。合并的条件是两块必须大小相等,地址相邻,其实地址较小的块必须是2的倍数。

二. 非连续内存分配

在连续内存分配中,要给进程分配内存,必须分配一块物理地址连续的内存区域,但是 这种方式并不太合理,内存利用效率低。

基于此,非连续内存分配就出现了,把内存分成很多的基本块,基本块的规模就出现了段式存储和页式存储。页式存储的块比较小,这就会导致从逻辑地址到物理地址的关系就会复杂起来,这就需要页表来描述这种对应关系。同时,也可以把段式和页式结合起来,就形成了段页式。

1.非连续内存分配的需求背景

连续分配的缺点 (内存分配的动态修改是指进程的分区大小变化时)


非连续分配的设计目标

  1. 允许一个程序的使用非连续的物理地址空间
  2. 允许各个进程共享代码与数据
  3. 支持动态加载和同台链接

需要解决的问题

2.段式存储管理

进程的段地址空间

在段存储管理中,将进程的地址空间看出是由多个段组成的


逻辑视图

段访问机制

段表示访问方式和存储数据等属性相同的一段地址空间。

段访问的话就是将逻辑地址分为段号+偏移量

3.页式存储管理 (页表、页框)

将内存分为很多小块,每个进程被分为同样大小的小块,每个进程维护了一个页表,页表给出了该进程中的每个页号对应的页框号(页框就是内存中可用的块)。

在程序中,每个逻辑地址包括页表中的一个页号和在该页中的偏移量。这样,处理器就能根据页表获取页框号,进而产生物理地址。

使用分页技术在内存中为每个进程浪费的空间仅仅是进程最后一页一小部分形成的内部碎片,没有外部碎片。

页和页框的用法




页式存储的实现

页的大小和页框的大小必须是2的幂






学习直通车

以上是关于清晰讲解Linux内核,连续内存分配与非连续内存分配(图例解析)的主要内容,如果未能解决你的问题,请参考以下文章

Linux 内核 内存管理内存管理架构 ③ ( Linux 内核中的内存管理模块 | 页分配器 | 不连续页分配器 | 内存控制组 | 硬件设备内存管理 | MMU | 页表缓存 | 高速缓存 )

RK3399平台开发系列讲解(内存篇)18.3kmalloc

linux内存池能分配连续物理内存吗

linux内核内存分配

linux内核中不连续页分配器

Linux内核内存管理算法Buddy和Slab