内存管理(一):内存寻址

总线

总线分工

  1. 数据总线:负责数据实际传输
  2. 地址总线:负责传输数据地址
  3. 控制总线:负责传输控制信号

取数据的时候CPU通过地址总线传输地址给内存,内存返回的数据通过数据总线传递给CPU

数据总线和地址总线决定因素

数据总线:CPU位数 -> 寄存器位数 -> 数据总线位数

地址总线:内存地址信号引脚数 -> 地址总线位数

大部分情况下:CPU位数 != 地址线位数,像8086CPU数据总线有16条,地址线有20条

年份 1978 1985 1993-2006 200至今
处理器CPU 8086 80386 Pentium系列 Core系列
CPU位数 16 32 32、64 64
地址总线位数 20 32 32、36、39 40、48可扩展

处理器名字:如果是Intel 32位体系结构叫x86,Intel 64位扩展体系结构叫X86-64

8086的分段寻址

CPU存储的位数是16位,它的寄存器只有16位,但是地址总线却有20位。如果不做特殊处理的话,CPU只能访问64KB内存,后面的内存无法访问到。

image-20230109214526711

分段寻址

解决方法:分段寻址

  1. 分段,将1MB内存分成多个64KB的段
  2. 通过段基址寄存器(16位)存储存储一段在内存中的基地址
  3. 段基地址左移 4 位并加上段内偏移,从而找到内存中的地址
  4. 想要访问其他段,那么段寄存器只需要存储其他段的段基址即可

image-20230109214044819

注:ip寄存器是指令寄存器,用来存储需要执行的指令在段中的偏移的。如果需要访问数据,则需要将数据的段内偏移加载到通用寄存器中。

8086的分段寻址

由于一个程序也需要分段:

image-20230109203519084

CPU有三个寄存器用来存储不同段的基址:

  • CS(Code Segment)寄存器
  • DS(Data Segment)寄存器
  • SS(Stack Segment)寄存器

注意:还有一个ES寄存器(附加段寄存器),这篇就先不给出来

  • 访问数据的时候:(DS << 4) + 段内偏移

  • 访问栈的时候:(SS << 4) + 段内偏移

  • 访问代码的时候:(CS << 4) + 段内偏移

image-20230109220055522

注意:每个程序自己的三个段基地址是不同的,CPU切换不同程序的时候,会切换段基地址寄存器的值

实模式的缺点

这个时期的8086处理器,所有操作都是在真实物理内存上,这个时候还没有操作系统这么一说。也没有权限控制,只要你驱动接口,就可以随意更改内存。这就是Linux所谓的“实模式”,安全性差。

一个程序有可能会不小心访问其他程序的数据,不安全,没有内存保护。

image-20230109223541218

80386的分段寻址

80386位处理器32位,地址总线有32根,可以访问4G的内存。不需要采用实模式,而是使用保护模式。当然由于80386是一个开放包容的处理器,它的保护模式是兼容实模式的。

注:80386实现分段是为了兼容,现代操作系统都不用分段寻址了,分段寻址只是一个过渡。

保护模式的分段寻址

  • 80386是32位处理器,8个通用寄存器从16位变为32位。

  • IP寄存器(16位)变为EIP寄存器(32位)

  • 段寄存器不再存储段起始地址,而是存储段选择子

image-20230110161245534

  • 段表中有段长度,如果段内偏移大于段长度则说明访问段外的内存,非法访问内存
  • 段表存储了权限,比如可读可写等,权限控制更加灵活
  • 保护模式是可以兼容实模式的,32位的寄存器既可以存储32位也能存储16位。

GDT和LDT

GDT(Global Descriptor Table)是全局描述符表。

LDT(Local Descriptor Table)局部描述符表。

LDT属于程序,GDT属于系统,同一台计算机上所有程序共享一个GDT。GDTR是GDT的寄存器,LDTR是LDT的寄存器

image-20230110161337660

分段寻址缺陷

  1. 容易产生内存碎片

  2. 当时8086处理器引入分段的目的是为了解决16位CPU寻址20位内存问题。但是现代操作系统都不用分段了。

  3. 现代操作系统为了兼容都保留了分段,但是基本都不用了。将段的起始地址设置位内存起始地址,将段长度设置为最大。把整个内存看成一段。

  4. 现代操作系统使用分页寻址。

    image-20230110163851110

分页寻址

分页

  • 将物理内存分为多个大小相等的物理页(Physical Page,PP),页的大小可以是:4KB,8KB,16KB..
  • 将每个程序的虚拟内存,分为多个大小相等的虚拟页(Virtual Page,VP),虚拟页大小等于物理页大小
  • 通过页表来确定虚拟页对应哪个物理页
  • 每个程序都有自己的页表,感觉自己拥有一个独立的虚拟内存

image-20230110204135430

地址转换

在虚拟地址空间中程序使用的是虚拟内存,那么CPU该如何通过虚拟地址来获取真实地址呢?

  • 虚拟地址由 虚拟页号 + 页内偏移 组成
  • 通过虚拟页号去页表中查询物理页号
  • 物理页号 + 页内偏移就是真实地址了

image-20230110210703912

  • 页内偏移选择的位数是根据页大小来确定的,比如页大小是64字节,那么虚拟地址的前6位做位页内偏移,2^6 = 64

分页寻址相关的硬件

  1. 页表基址寄存器(PTBR):用于存储页表在内存中的基地址,用于找到页表在内存中的位置
  2. 内存管理单元(MMU):CPU将虚拟地址给到MMU,MMU将虚拟地址转换为物理地址

image-20230111000137378

MMU工作方式:

  1. 通过页表基址寄存器,找到页表的起始地址
  2. 通过虚拟页号和页表起始地址,找到页表项的位置
  3. 读取物理页号
  4. 物理页号+页内偏移就是物理地址

image-20230104160644830

多级页表

  • 解决单个页表项过多、页表过大可以采用多级页表
  • 通过一级页表去找二级页表的页表起始地址,通过二级页号到二级页表中找到二级页表的页表项

image-20230104162916740