关于逻辑地址、线性地址、虚拟地址、物理地址的理解

服务器

浏览数:205

2019-6-27

最近在看《深入理解Linux内核》,在第二章《内存寻址》中提到了逻辑地址、线性地址、虚拟地址、物理地址的概念。

原文是这么描述的:

逻辑地址(logical address):
包含在机器语言指令中用来指定一个操作数或一条指令的地址。这种寻址方式在80x86著名的分段结构中表现得尤为具体,它促使MS-DOS或Windows程序员把程序分成若干段。每一个逻辑地址都由一个段(segmemt)和偏移量(offset或displacememt)组成,偏移量指明了从段开始的地方到实际地址之间的距离。
    
线性地址(linear address)(也称虚拟地址 virtual address):
是一个32为无符号整数,可以用来表示高达4GB的地址,也就是,高大4 294 967 296个内存单元。线性地址通常用十六进制数字表示,值的范围从0x00000000到0xffffffff。
    
物理地址(physical address):
用于内存芯片级内存单元寻址。它们与从微处理器的地址引脚发送到内存总线上的电信号相对应。物理地址由32位或36位无符号整数表示。

在文中,把线性地址和虚拟地址等同,并详细定义了逻辑地址。但是,把逻辑地址的定义套入到我们平时交流中提到的逻辑地址定义,怎么这么别扭呢?

在工作中,我们经常把逻辑地址等同于虚拟地址,基本不用线性地址,例如对于以下C程序:

#include <stdio.h>
#include <stdlie.h>

int main(int argc, char **argv)
{
    int var = 1;
    char *mvar = malloc(10);
    printf("var address: %p\n", &var);
    printf("mvar address: %p\n", &mvar);
}

执行的结果

[GMPY@17:04 tmp]$./test 
var address: 0x7ffe9ddceb9c
mvar address: 0x7ffe9ddceba0

我们在工作中交流时,经常把上面打印出来的地址叫做虚拟地址,有时候也会叫做逻辑地址,而非书中这么复杂这么绕人的概念。

那么,我们究竟怎么区分这几个地址?

关于逻辑地址的理解

在《深入理解Linux内核》中描述了 在80×86处理器中 地址的转换:

逻辑地址 -> [分段单元] ->线性地址 -> [分页单元] -> 物理地址

其中 分段单元分页单元 是硬件电路,分别用于 从逻辑地址到虚拟地址从虚拟地址到物理地址的转换。注意的是,作者特意强调了 在80×86处理器中

在书中 Linux中的分段 小章节得出一个非常重要的结论:

这可以得出另一个重要结论,在Linux下逻辑地址与线性地址是一致的,即...

在Linux下逻辑地址与线性地址是一致的!!

既然是一致的,为什么还要区分逻辑地址和线性地址?历史已经不可究,但不妨碍我 瞎想 遐想:

Intel体系下的工程师提出分段的特点时,为了区别分段与分页前的地址,苦思冥想后造出了逻辑地址的概念

为什么要强调是Intel体系呢?因为 以intel为代表的有限的一些体系规定了要用分段+分页(arm体系貌似只有分页)。实际上 与分段相比,Linux更喜欢使用分页方式,换句话说,Linux不喜欢用分段,但是为了兼容,只能走走形式,意思意思一下,在实现中让逻辑地址虚拟地址

结论

如果非要定义逻辑地址,我们可以把逻辑地址简单理解为

为了区分分段与分页的地址,把分段前的地址叫做逻辑地址,把分页前的地址叫做虚拟地址

在Linux中,我们可以认为 逻辑地址=虚拟地址=线性地址,因此只剩下两类地址:

虚拟地址:cpu访问的地址,即C语言中"%p"打印出来的地址
物理地址:物理内存实际地址,经过MMU从虚拟地址转换而来

上述仅仅是个人理解,如果有不对的地方,希望一起交流

作者:广漠飘羽