首页 > 系统相关 >《Linux内核完全注释》学习笔记:2.5 Linux内核对内存的使用方法

《Linux内核完全注释》学习笔记:2.5 Linux内核对内存的使用方法

时间:2024-06-02 23:01:11浏览次数:22  
标签:地址 内存 Linux 线性 CPU 2.5 内核

在Linux 0.11内核中,为了有效地使用机器中的物理内存,

内存被划分成几个功能区域,如图2-9所示。
image
图2-9 物理内存使用的功能区域分布图

  1. Linux内核程序占据在物理内存的开始部分,
  2. 接下来是用于供硬盘或软盘等块设备使用的高速缓冲区部分。

当一个进程需要读取块设备中的数据时,系统会首先将数据读到高速缓冲区中;
当有数据需要到块设备上去时,系统也是先将数据放到高速缓冲区中,然后由块设备驱动程序写到设备上。

  1. 最后部分是供所有程序可以随时申请使用的主内存区。
  • 内核程序在使用主内存区时,也同样要首先向内核的内存管理模块提出申请,在申请成功后方能使用。
  • 对于含有RAM虚拟盘的系统,主内存区头部还要划去一部分,供虚拟盘存放数据。

由于计算机系统中所含的实际物理内存容量是有限的,因此CPU中通常都提供了内存管理机制对系统中的内存进行有效的管理。

在Intel CPU中,提供了两种内存管理(变换)系统:

  • 内存分段系统(Segmentation System)
  • 分页系统(Paging System)。

而分页管理系统是可选择的,由系统程序员通过编程来确定是否采用。为了能有效地使用这些物理内存,Linux系统同时采用了Intel CPU的内存分段和分页管理机制。

在Linux 0.11内核中,当进行地址映射时,我们需要首先分清3种地址以及它们之间的变换概念:

  1. 程序(进程)的逻辑地址;
  2. CPU的线性地址;
  3. 实际物理内存地址。

1.逻辑地址(Logical Address)
是指由程序产生的与段相关的偏移地址部分。

在Intel保护模式下就是指程序执行代码段限长内的偏移地址(假定代码段、数据段完全一样)。

应用程序员仅需与逻辑地址打交道,而分段和分页机制对他来说是完全透明的,仅由系统编程人员涉及。

2.线性地址(Linear Address)
是逻辑地址到物理地址变换之间的中间层。
程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。

如果启用了分页机制,那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4GB。

3.物理地址(Physical Address)
是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。
如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了。


虚拟内存(Virtual Memory)
是指计算机呈现出要比实际拥有的内存大得多的内存量。
因此它允许程序员编制并运行比实际系统拥有的内存大得多的程序。这使得许多大型项目也能够在具有有限内存资源的系统上实现。

一个很恰当的比喻是:你不需要很长的轨道就可以让一列火车从上海开到北京。你只需要足够长的铁轨(比如说3km)就可以完成这个任务。采取的方法是把后面的铁轨立刻铺到火车的前面,只要你的操作足够快并能满足要求,列车就能像在一条完整的轨道上运行。

这也就是虚拟内存管理需要完成的任务。在Linux 0.11内核中,给每个程序(进程)都划分了总容量为 64MB 的虚拟内存空间。因此程序的逻辑地址范围是 0x0000000 到 0x4000000。

64MB = 2^(6+10+10)
0x4000'000 6*4+2=26 位

有时我们也把逻辑地址称为虚拟地址。因为与虚拟内存空间的概念类似,逻辑地址也是与实际物理内存容量无关的。


在内存分段系统中,一个程序的逻辑地址是通过分段机制自动地映射(变换)到中间层的线性地址上。每次对内存的引用都是对内存段中内存的引用。当一个程序引用一个内存地址时,通过把相应的段基址加到程序员看得见的逻辑地址上就形成了一个对应的线性地址。此时若没有启用分页机制,则该线性地址就被送到CPU的外部地址总线上,用于直接寻址对应的物理内存。
若采用了分页机制,则此时线性地址只是一个中间结果,还需要使用分页机制进行变换,再最终映射到实际物理内存地址上。与分段机制类似,分页机制允许我们重新定向(变换)每次内存引用,以适应我们的特殊要求。

使用分页机制最普遍的场合是当系统内存实际上被分成很多凌乱的块时,它可以建立一个大而连续的内存空间的映像,好让程序员不用操心和管理这些分散的内存块。

分页机制增强了分段机制的性能。页地址变换是建立在段变换基础之上的。任何分页机制的保护措施并不会取代段变换的保护措施,而只是进行更进一步的检查操作


因此,CPU进行地址变换(映射)的主要目的是为了解决虚拟内存空间到物理内存空间的映射问题

虚拟内存空间的含义是指一种利用二级或外部存储空间,使程序能不受实际物理内存量限制而使用内存的一种方法。通常虚拟内存空间要比实际物理内存量大得多。

那么虚拟内存空间管理是怎样实现的呢?
原理与上述列车运行的比喻类似。

  1. 首先,当一个程序需要使用一块不存在的内存时(即在内存页表项中已标出相应内存页面不在内存中),CPU就需要一种方法来得知这个情况。

这是通过80386的页错误异常中断来实现的。

  1. 当一个进程引用一个不存在页面中的内存地址时,就会触发 CPU 产生页出错异常中断,并把引起中断的线性地址放到 CR2 控制寄存器中。
  2. 因此处理该中断的过程就可以知道发生页异常的确切地址,从而可以把进程要求的页面从二级存储空间(比如硬盘上)加载到物理内存中。
  3. 如果此时物理内存已经被全部占用,那么可以借助二级存储空间的一部分作为交换缓冲区(swapper)把内存中暂时不使用的页面交换到二级缓冲区中,然后把要求的页面调入内存中。

这就是内存管理的缺页加载机制,在Linux 0.11内核中是在程序 mm/memory.c 中实现的。


Intel CPU使用段(segment)的概念来对程序进行寻址。
每个段定义了内存中的某个区域以及访问的优先级等信息。
而每个程序都可由若干个内存段组成。
程序的逻辑地址(或称为虚拟地址)即是用于寻址这些段和段中具体地址位置。
在Linux 0.11中,程序逻辑地址到线性地址的变换过程使用了 CPU 的全局段描述符表 GDT 和局部段描述符表 LDT 。

  • 由 GDT 映射的地址空间称为全局地址空间,
  • 由 LDT 映射的地址空间则称为局部地址空间,

而这两者构成了虚拟地址空间。具体的使用方式见图2-10。
图中画出了具有两个任务时的情况。对于中断描述符表 IDT ,它是保存在内核代码段中的。由于在Linux 0.11内核中,内核和各任务的代码段和数据段都分别被映射到线性地址空间中相同基址处,且段限长也一样,因此内核和任务的代码段和数据段都分别是重叠的。另外,Linux 0.11内核中没有使用系统段描述符。

内核和各任务的代码段和数据段都分别被映射到线性地址空间中相同基址处,且段限长也一样,因此内核和任务的代码段和数据段都分别是重叠的。
这段话理解上很奇怪,线性地址空间怎么会是重叠的呢?按照 2.4 节的说法是指任务 0 与内核的重叠吗?可是前面说的又是内核和各任务的……还是说这个线性地址空间实际上应该理解位虚拟地址或者说逻辑地址才对。

image
图2-10 Linux系统中虚拟地址空间分配图


内存分页管理的基本原理是将整个主内存区域划分成以 4096B 为一页的内存页面。
程序申请使用内存时,就以内存页为单位进行分配。在使用这种内存分页管理方法时,每个执行中的进程(任务)可以使用比实际内存容量大得多的连续地址空间。对于Intel 80386系统,其CPU可以提供多达4GB的线性地址空间。
对于Linux 0.11内核,系统设置全局描述符表GDT中的段描述符项数最大为256,其中两项空闲、两项系统使用,每个进程使用两项。
因此,此时系统可以最多容纳 (256-4)/2=126 个任务,并且虚拟地址范围是 (256-4)/2×64MB 约等于 8GB。
但0.11内核中人工定义最大任务数 NR_TASKS=64 个,每个进程虚拟地址范围是64MB,并且各个进程的虚拟地址起始位置是任务号×64MB。因此所使用的虚拟地址空间范围是 64MB×64=4GB,如图2-11所示。4GB正好与CPU的线性地址空间范围或物理地址空间范围相同,因此在0.11内核中比较容易混淆三种地址概念。
image
图2-11 Linux 0.11虚拟地址空间的使用示意图

进程的虚拟地址需要

  1. 首先通过其局部段描述符变换为 CPU 整个线性地址空间中的地址,
  2. 然后再使用页目录表PDT(一级页表)和页表PT(二级页表)映射到实际物理地址页上。因此两种变换不能混淆。

为了使用实际物理内存,每个进程的线性地址通过二级内存页表动态地映射到主内存区域的不同内存页上。因此每个进程最大可用的虚拟内存空间是64MB。每个进程的逻辑地址通过加上任务号×64MB,即可转换为线性地址。不过在注释中,我们通常将进程中的地址简单地称为线性地址。
有关内存分页管理的详细信息,可参见第10章开始部分的有关说明。
从Linux内核0.99版以后,对内存空间的使用方式发生了变化。每个进程可以单独享用整个4GB的地址空间范围。由于篇幅所限,这里对此不再说明。


说实话笔记做完也还是有一堆疑惑不解的,有些地方的问题我都在想到底是错字还是我没有理解的关系。
下面给出的参考文章多了一部分的内容有助于理解但也依然没有完全解惑,希望读下去后能解惑吧。

参考文章:
Linux 0.11 中的内存地址空间概念 | 糖醋鱼的小破站

标签:地址,内存,Linux,线性,CPU,2.5,内核
From: https://www.cnblogs.com/Larcvz/p/18227781

相关文章

  • 【Linux系统编程】冯诺依曼体系、操作系统、进程的认识
    目录一、认识冯诺依曼体系二、认识操作系统三、认识进程一、认识冯诺依曼体系我们日常使用的计算机,笔记本和我们不常见的计算机如服务器,它们都遵循冯诺依曼体系。下图是冯诺依曼体系结构的图解:我们可以看到冯诺依曼体系结构由以下硬件组成:输入设备、输出设备、存储器......
  • Shell 脚本演示 Linux 中的 Wait 命令
    Wait命令是进程管理命令之一。Linux中有不同的进程命令,主要使用5个命令,它们是ps、wait、sleep、kill、exit。ps是进程状态的缩写。它显示有关活动进程的信息。wait命令将暂停调用线程的执行,直到其子进程之一终止。它将返回该命令的退出状态。sleep命令用于将下一个命令的执行......
  • springboot本地运行正常,打包jar包上传Linux服务器后报错,无法正常运行解决方法
    问题描述:springboot本地运行正常,打包jar包上传Linux服务器后报错,无法正常运行说明:以下两种打包方式均在IDEA软件内完成,上传服务器使用宝塔面板管理1.第一次打包方式; 设置完打包路径后,进入build菜单进行打包:  选择build或rebuild进行打包,打包后上传jar包到服务器,运......
  • linux服务器硬件及RAID配置实战
    RAID磁盘阵列介绍是RedundantArrayofIndenpendentDisks的缩写,中文简称为独立冗余磁盘阵列把多个独立的物理硬盘按不同的方式组合起来形成一个硬盘组(逻辑硬盘),从而提供比单个硬盘更高的存储性能和提供数据备份技术。组成磁盘阵列的不同方式称为RAID级别(RAIDLevels)常用......
  • 【Linux 网络】网络基础(三)(其他重要协议或技术:DNS、ICMP、NAT)
    一、DNS(DomainNameSystem)DNS 是一整套从域名映射到 IP 的系统。1、DNS 背景TCP/IP 中使用 IP 地址和端口号来确定网络上的一台主机的一个程序,但是 IP 地址不方便记忆。于是人们发明了一种叫主机名的东西,是一个字符串,并且使用 hosts 文件来描述主机名......
  • U-boot、linux内核、根文件系统移植以及程序
    终于这几天把这个移植的流程过了一遍,所以特此回来总结。U-boot移植首先是U-boot移植。Linux系统要启动就必须需要一个bootloader程序,也就说芯片上电以后先运行一段bootloader程序。这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND,NORFLASH,SD,MMC等)拷......
  • Linux下GMAC网络设备:硬件接口、GMAC/PHY、驱动、测试程序
    1嵌入式网络硬件接口如下是常见的嵌入式网络硬件接口框图:SOC集成MAC。MAC通过MII系列接口和PHY之间传输数据,通过MDIO接口初始化配置PHY芯片。PHY芯片和RJ45之间通过4组差分模拟信号传输数据,并驱动RJ45的LED信号灯。RJ45通过网线和外部连接。1.1嵌入式网络几种常见架构......
  • Linux-shell的108个案例
    通用函数库#catdiy_func.shredecho(){ #颜色开头部分 echo-ne"\e[5;31m" #取出要加上颜色的内容 echo-n"$@" #颜色的结束部分 echo-e"\e[0m" #echo-e"\e[5;31m$@\e[0m"}greenecho(){ echo-ne"\e[1;32m" ec......
  • Linux-samba-Ubuntu
    sudoaptinstallsamba-ymkdir-pSharechmod0777Sharesudocp/etc/samba/smb.conf/etc/samba/smb.conf.baksudovim/etc/samba/smb.conf[Ubuntu_22.04] comment=Samba path=/home/grayson/Share public=yes writable=yes available=yes browsea......
  • Linux 进程
    1.什么叫进程答:一个已经加载到内存的程序,叫进程(任务);1.1一个操作系统可以运行多个进程,可以跑多个任务;1.2任何一个进程,在加载到内存的时候,形成真正的进程,操作系统要先创建描述进程的结构体对象——PCB,processctrlblock——进程控制块(进程属性的集合)——struct结构体1.3 ......