在说Linux的内存管理之前,先说一下X86的内存管理方式。
16位的CPU内部拥有20位地址总线,它的寻址范围是2的20次方,也就是1M的内存空间,数据总线却有16位,16位CPU用于存放地址的寄存器(IP,SP ......)只有16位,因此能有访问65535个存储空间,也就是64K。为了能够访问1M的存储空间,CPU采用了内存分段的管理模式,并在CPU内部加入了段寄存器,16位CPU把1M的空间分为若干个逻辑段,每个逻辑段的起始地址(段地址)必须是16的倍数,即最后4个二进制位必须全为0,逻辑段的最大容量为64K。
逻辑地址= 段基地址+段内偏移量 由逻辑地址得到物理地址的公式为:PA=段寄存器的值 x 16(得到基址) + 逻辑地址(乘以16是因为16位的寄存器存的是20位的地址,由上知最后4位为0,所以存的时候不存,即只存高16位,也就相当于左移4位,所以计算时需要右移4位,也就是乘以16)
下面来说一下逻辑地址,线性地址,物理地址,和虚拟地址的区别:
线性地址:是逻辑地址到物理转换的中间层,连续的,不分段的0~4G的地址空间(有时也称为虚拟地址)。
物理地址:也就是实际地址,就是地址总线所访问的地址。
逻辑地址:(也叫相对地址)按Intel说的定义是由一个段标识符加上一个指定段内的相对地址偏移量(也可以理解成代码中去地址符号后得到的地址)。例如变量A的地址为0x80000000,则A的逻辑地址为【A的段代码标识符:0x80000000】
不同的逻辑地址可以映射到相同的线性地址上(因为段的基址不同),不同的线性地址也可以映射到相同的物理地址上(因为所使用的页目录和页表不同),多是多对一的关系。
CPU为32位时,分为实模式和保护模式,实模式时和16的CPU 是一样的,而保护模式采用的分段机制和分页机制。
从逻辑地址到线性地址的转换过程为:首先从
段选择符寄存器中找到相应的
段描述符的索引,然后从
段描述符中读出相应的段的基址和偏移量。
段的基址(放在段的基址寄存器中)+偏移量= 线性地址。
从线性地址到物理地址的转换过程为:(若没有启动分页机制则线性地址就是物理地址)从
CR3寄存器(进程运行时操作系统自动把页目录地址存到CR3寄存器中)取出
页目录地址。
CR3中取出的页目录地址 + 线性地址的最高10位[31 :22] = 页表地址
页表地址 + 线性地址的中间10位[21 : 12] = 物理页的起始地址
物理页的起始地址 + 最后12的偏移地址 = 物理地址
图形如下:
采用的是二级管理模式:即页目录表中项不是页的地址,而是页表的地址,还有采用三级管理模式,四级管理模式的,此时的线性地址就不是32位了,而是64位。分页的大小有64K的,有4k的,也有极小页1k的,当以4K分页时,4GB=4k x 2的20次方,也就是有2的20次方个页,至于为什么可以覆盖4G的线性地址空间的计算过程为:页目录中有2的10次方个页表(线性地址的最高10位),而一个页表中有2的10次方个也(中间10位),一个页中又有2的12次方个偏移地址,所以连乘后刚好为4G。
物理的地址的分页的大小和页的分页大小是一样的,段的长度不是固定的,页的长度是固定的。
最后说一下Linux的内存管理:Linux的内存管理可以说是完全的分页管理机制,页可以说是有限的采用了分页管理机制,因为所有的段的基址都是0,由此得出每个段的逻辑地址空间范围都是0~4G,因此逻辑地址与线性地址保持一致(即逻辑地址偏移量的字段的值总是与线性地址是一样的),在Linux中提到的逻辑地址(相对地址)和线性地址(虚拟地址)可以认为是一样的,看来Linux巧妙的把分段机制给避过去了,完全采用分也地址,说有限的采用时所有段的机制都是0.
Linux的页式地址管理图如下:
Linux把虚拟地址空分为两部分,用户地址空间和内核地址空间,从0~0xbfffffff为用户地址空间,3G到4G为内核地址空间,
阅读(1293) | 评论(0) | 转发(0) |