zoukankan      html  css  js  c++  java
  • Linux内存管理(一)

    Linux内存管理之一:基本概念篇

    物理地址、线性地址(虚拟地址)和逻辑地址;阐述段式管理和页式管理基本概念;Linux操作系统内存管理和虚拟内存概念;为内核开发做一个基础铺垫。

    内存是linux内核所管理的最重要的资源之一,内存管理子系统是操作系统中最重要的部分之一。对与立志从事内核开发的工程师来说,熟悉linux的内存管理系统非常重要。

    1、物理地址、线性地址(虚拟地址)和逻辑地址之间的关系

    物理地址是指出现在cpu外部的地址总线上的寻址物理内存的地址信号,是地址变换的最终结果。

    逻辑地址是程序代码经过编译后在汇编程序中使用的地址。

    线性地址又名虚拟地址,在32位cpu框架下,可以表示4G地址空间,用16进制表示就是0x00000000到0xffffffff。

    地址转换:cpu要将一个逻辑地址转换为物理地址,需要两步:首先cpu利用段式内存管理单元,将逻辑地址转换成线性地址,在利用页式内存管理单元,把线性地址最终转换为物理地址。

    2.段式管理与页式管理

    什么是段式管理?

    16位cpu内部拥有20位的地址线,它的寻址范围就是2的20次方,也就是1M的内存空间。但是16位的菜谱用于存放地址的寄存器只有16位,因此只能访问65536个存储单元,64K。为了能够访问1M的内存空间,cpu就采用了内存分段的管理模式,并在cpu内部加入了段寄存器。16位cpu把1M内存空间分为若个逻辑段,每个逻辑段的要求如下:

    1、 逻辑段的起始地址(段地址)必须是16的倍数,即最后4个二进制必须全为0.

    2、 逻辑段的最大容量为64K

    物理地址的形成方式:

    由于段地址必须是16的倍数,所以值的一般形式为XXXX0H,即前16位二进制位是变化的,后4位是固定的0,鉴于段地址的这种特性,可以只保存前16位二进制位来保存这个段基地址,所以每次使用时要用段寄存器左移4个0(乘以16)来得到实际的段地址。在确定了某个存储单元所属的段后,只是知道了该存储单元所属的范围(段地址->段地址+65536),如果想确定该存储单元的具体位置,还必须知道该单元在段内的偏移。有了段地址和偏移量,就可以唯一的确定内存单元在存储器中具体位置。

    逻辑地址=段内偏移量

    由于逻辑地址得到物理地址的公式为:PA=段寄存器的值*16+逻辑地址

    段寄存器是为了对内存进行分段管理而增加的,16位cpu有四个段寄存器,程序可同时反问四个不同含义的段。

    1、CS+IP:用于代码段的访问,CS指向存放程序的段基址,IP指向下条要执行的指令在CS段的偏移量,用这两个寄存器就可以得到一个内存物理地址,该地址存放着一条要执行的指令。

    2、SS+SP:用于堆栈段的访问,SS指向堆栈段的基地址,SP指向栈顶,可以通过SS和SP两个寄存器直接访问栈顶单元的内存物理位置。

    3、DS+BX:用于数据段的访问。DS中的值左移四位得到数据段起始地址,再加上BX中的偏移量,得到一个存储单元的物理地址。

    4、ES+BX:用于附加段的访问。ES中的值左移四位得到附加段起始地址,再加上BX中的偏移量,得到一个存储单元的物理地址。

    32位pc的内存管理能然采用“分段”的管理模式,逻辑地址同样由段地址和偏移量两部分组成,32位pc的内存管理和16位pc的内存管理有相同之处,也有不同之处,因为32位pc采用了两种不同的工作方式:实模式和保护模式。我们一般使用在保护模式的。

    1、 实模式

    在实模式下,32位的cpu的内存管理与16位的cpu是一致的。

    2、 保护模式

    段基地址长达32位,每个段的最大容量可达4G,段寄存器的值是段地址的“选择器”(Selector),用该“选择器”从内存中得到一个32位的段地址,存储单元的物理地址就是该段地址加上段内偏移量,这与32位cpu的物理地址计算方式完全不同。

    32位cpu内有6个段寄存器,其值在不同的模式下具有不同的含义:

    1、 在实模式下:

    段寄存器的值*16就是段地址

    2、 在保护模式下:

    段寄存器的值就是一个选择器,间接指出一个32位的段地址

    什么是页式管理?

    从管理和效率的角度出发,线性地址被划分为固定长度的组,称为页(page),例如32位的 ,线性地址最大可为4G,如果用4KB为一个也来划分,这样的这个线性地址就被划分为2的20次方个页。

    另一类“页”,也称之为“物理页”,或者是页框、页帧。分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与线性地址页是相同的。

    1、 分页单元中,页目录的地址放在cpu的cr3寄存器中,是进行地址转换的开始点。

    2、 每个进程,都有其独立的虚拟地址空间,运行一个进程,首先需要在它的页目录地址放到cr3寄存器中,将其他进程的保存下来。

    3、 每个32位的线性地址被划分为三个部分:页目录索引(10位),页表索引(10位):偏移(12位即4k)。

    依据一下步骤进行地址转换:

    1、 装入进程的页目录地址(操作系统在调度进程时,把这个地址装入cr3)

    2、 根据现行线性地址的前10位,在页目录中找对应的索引项,页目录中的项是一个页表的地址。

    3、 根据线性地址的中间10位,在页表中找到页的起始地址。

    4、 将页的起始地址与线性地址的最后12位相加,得到物理地址。

    这样的二级模式是可以覆盖4G的物理地址空间的,

    页目录中共有:2^10项,也就是说有这么多个页表;页表对应有:2^10页;每个页可寻址:2^12个字节。即2^32=4GB。

    3.Linux内存管理

    Linux内核的设计并没有全部采用Intel所提供的段机制,仅仅是有限度地使用了分段机制。这不仅简化了linux内核的设计,而且为把linux移植到其他平台创造了条件,因为很多RISC处理器并不支持段机制。

    在linux中,所有段的基地址均为0,由此可以得出,每个段的逻辑地址空间范围是0-4GB。因为每个段的基地址为0,因此逻辑地址与线性地址保持一致(即逻辑地址的偏移量字段的值与线性地址的值总是相同的),在linux中所提到的逻辑地址和线性地址(虚拟地址),可以认为是一致的。看来,linux巧妙地把段机制给绕过去了,而完全利用了分页机制。

    前面介绍的是i386的二级管理架构,不过有的cpu使用的三级,甚至是四级架构,linux2.6.29内核为每种cpu提供统一的界面,采用了四级页面管理架构来兼容二级、三级、四级管理架构的cpu。

    这四级分别为:

    1、 页全局目录(Page Global Directory):即pgd,是多级页表的抽象最高层。

    2、 页上级目录(Page Upper Directory):即pud。

    3、 页中间目录(Page Middle Directory):即pmd,是页表的中间层。

    4、 页表(Page Table Entry):即pte

    4.虚拟内存

    Linux操作系统采用虚拟内存管理技术,使得每个进程都有一个独立的进程地址空间,该空间是大小为3G,用户所看到和接触的都是虚拟地址,无法看到实际的物理地址。利用这种虚拟地址不但能起到保护操作系统的作用,而且更重要的是用户程序可使用比实际物理内存更大的地址空间。

    Linux4G的虚拟地址空间划分为两个部分---用户空间和内核空间。用户空间从00xbfffffff,内核空间从3G4G。用户进程通常情况下只能访问用户空间的虚拟地址,不能访问内核空间。例外情况是用户进程通过系统调用访问内核空间。

  • 相关阅读:
    解释DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
    MySQL性能优化
    MySQL中的binlog相关命令和恢复技巧
    保障MySQL安全的14个最佳方法
    MySQL忘记root密码的解决方案
    MySQL利用binlog来恢复数据库
    MySQL命令mysqldump参数大全
    MySQL REPLACE替换输出
    MySQL -A不预读数据库信息(use dbname 更快)
    MySQL 慢查询配置
  • 原文地址:https://www.cnblogs.com/tslDream/p/4750530.html
Copyright © 2011-2022 走看看