物理/逻辑/虚拟内存地址之间的差异

gst*_*gst 26 operating-system virtual-memory linux-kernel

我对操作系统中的物理/逻辑/虚拟地址这个术语感到有点困惑(我使用的是Linux-open SU​​SE)

这是我的理解:

  1. 物理地址 - 当处理器处于系统模式时,处理器使用的地址是物理地址.

  2. 逻辑地址 - 当处理器处于用户模式时,使用的地址是逻辑地址.通过添加带有偏移值的基址寄存器,这些都可以映射到某个物理地址.它在某种程度上提供了一种内存保护.

  3. 我遇到过讨论,虚拟和逻辑地址/地址空间是相同的.这是真的吗?

非常感谢任何帮助.

Fin*_*fin 46

对于在现代Linux系统上运行的Intel CPU,我的答案是正确的,我说的是用户级进程,而不是内核代码.不过,我认为它会给你足够的洞察力来考虑其他可能性

地址类型

关于问题3:

我遇到过讨论,虚拟和逻辑地址/地址空间是相同的.这是真的吗?

据我所知,它们是相同的,至少在现代操作系统中运行在英特尔处理器之上.

在我解释更多之前,让我尝试定义两个概念:

  • 物理地址:物理位于RAM芯片中的地址.
  • 逻辑/虚拟地址:程序用于访问其内容的地址.它通常由硬件芯片转换为物理地址(大多数情况下,甚至CPU都不知道这种转换).

虚拟/逻辑地址

虚拟地址很好,一个虚拟地址,操作系统以及一个称为MMU(内存管理单元)的硬件电路,它使你的程序在系统中单独运行,它有整个地址空间(拥有32位系统意味着你的程序会认为它有4 GB的RAM;粗略地说.

显然,如果你当时有多个程序运行(你总是这样做,GUI,初始化程序,Shell,时钟应用程序,日历等等),这将无法正常工作.

会发生什么事情,操作系统会把你的大部分程序内存放在硬盘上,你使用最多的部分会出现在RAM中但是嘿,这并不意味着他们会拥有你知道的地址.

示例:您的进程可能有一个名为(counter)的变量,该变量给定虚拟地址0xff(可以想象...),另一个名为(oftenNotUsed)的变量给定虚拟地址(0xaa).

如果你在所有链接发生后读取已编译代码的程序集,你将使用这些地址访问它们,但是,(常常未使用的)变量将不会真正存在于0xaa的RAM中,它将位于硬盘中因为你没有使用它

此外,变量(计数器)可能不会在物理上处于(0xff),它将在RAM中的其他位置,当您的CPU尝试获取0xff中的内容时,MMU和操作系统的一部分将执行映射从RAM中真正可用的位置获取该变量,您甚至不会注意到它不在0xff中.

现在如果您的程序要求(通常不使用)变量会发生什么?MMU +操作系统会注意到这个"未命中"并将它从硬盘中取出并送到RAM中,然后将它交给你,就好像它在地址(0xaa)中一样; 这个提取意味着RAM中存在的一些数据将被发送回硬盘.

现在假设这个系统中的每个进程都在运行.每个人都认为他们有4GB的RAM,没有人真的拥有,但一切正常,因为每个人都有他们的程序的一些部分在RAM中物理可用,但大多数程序驻留在HardDisk.不要将放入HD的程序存储器的这一部分与您可以通过文件操作访问的程序数据混淆.

摘要

虚拟地址:您在程序中使用的地址,CPU用于获取数据的地址,不是真实的,并通过MMU转换为某个物理地址; 每个人都有一个,它的大小取决于你的系统(Linux运行32位有4GB的地址空间)

物理地址:如果您在操作系统上运行,则永远不会达到的地址.这是您的数据,无论其虚拟地址如何,都驻留在RAM中.如果您的数据来回发送到硬盘以便为其他进程提供更多空间,则会发生这种情况.

我上面提到的所有内容虽然是整个概念的简化版本,但却被称为计算机系统的内存管理部分.

这个系统的后果

  • 进程无法访问彼此的内存,每个人都有自己独立的虚拟地址,每个进程都会对不同的区域进行不同的转换,即使有时您可能会查看并发现两个进程尝试访问同一个虚拟地址.
  • 这个系统很适合作为缓存系统,你通常不使用你可用的整个4GB,那么为什么要浪费呢?让其他人分享并让他们也使用它; 当你需要更多时,你将从高清中取出你的数据并取代他们的数据,当然是要付出代价.

  • 我觉得它比选择的答案更有帮助.谢谢你的写作. (3认同)

Ale*_*nze 10

物理地址 - 当处理器处于系统模式时,处理器使用的地址是物理地址.

不一定是真的.这取决于特定的CPU.在x86 CPU上,一旦启用了页面转换,所有代码都停止使用物理地址或可以轻松转换为物理地址的地址(SMM,AFAIK除外,但这里并不重要).

逻辑地址 - 当处理器处于用户模式时,使用的地址是逻辑地址.通过添加带偏移值的基址寄存器,这些都可以映射到某个物理地址.

逻辑地址不一定仅适用于用户模式.在x86 CPU上,它们也存在于内核模式中.

我遇到过讨论,虚拟和逻辑地址/地址空间是相同的.这是真的吗?

这取决于特定的CPU.可以配置x86 CPU,以便不显式使用段.隐式使用它们,它们的基数始终为0(线程局部存储段除外).从逻辑地址中删除段选择器时剩下的是32位(或64位)偏移量,其值与32位(或64位)虚拟地址重合.在这种简化的设置中,您可以认为两者相同或逻辑地址不存在.这不是真的,但对于大多数实际目的而言,足够接近.


小智 6

用户虚拟地址 这些是用户空间程序看到的常规地址。用户地址的长度为 32 位或 64 位,具体取决于底层硬件架构,并且每个进程都有自己的虚拟地址空间。

物理地址 处理器和系统内存之间使用的地址。物理地址是 32 位或 64 位数量;在某些情况下,甚至 32 位系统也可以使用 64 位物理地址。

总线地址 外设总线和内存之间使用的地址。它们通常与处理器使用的物理地址相同,但情况不一定如此。当然,总线地址高度依赖于体系结构。

内核逻辑地址 这些构成了内核的正常地址空间。这些地址映射了大部分或全部主存储器,并且通常被视为物理地址。在大多数体系结构中,逻辑地址及其关联的物理地址仅存在恒定的偏移量。逻辑地址使用硬件的本机指针大小,因此可能无法寻址装备齐全的 32 位系统上的所有物理内存。逻辑地址通常存储在 unsigned long 或 void * 类型的变量中。从 kmalloc 返回的内存有一个逻辑地址。

内核虚拟地址 与逻辑地址的不同之处在于它们不一定具有到物理地址的直接映射。所有逻辑地址都是内核虚拟地址;vmalloc分配的内存也有虚拟地址(但没有直接的物理映射)。函数 kmap 返回虚拟地址。虚拟地址通常存储在指针变量中。

如果您有逻辑地址,则宏 __pa()(在 中定义)将返回其关联的物理地址。可以使用 __va() 将物理地址映射回逻辑地址,但仅限于低内存页。

参考。


Nis*_*ami 5

我指的是基于intel x86 CPU的以下答案

逻辑到虚拟地址之间的区别

无论何时程序正在执行,CPU都会为包含(16位段选择器和32位偏移)的指令生成逻辑地址.基本上,使用逻辑地址字段生成虚拟(线性地址).

段选择器是16位字段,其中第一个13位是索引(这是指向段描述符的指针驻留在GDT中,如下所述),1位TI字段(TI = 1,参考LDT,TI = 0参考GDT)

现在段选择器或者说段标识符是指代码段或数据段或堆栈段等.Linux包含一个GDT/LDT(全局/局部描述符表),其中包含每个段的8字节描述符并保存基本(虚拟)地址分割.

因此,对于每个逻辑地址,使用以下步骤计算虚拟地址.

1)检查段选择器的TI字段以确定哪个描述符表存储段描述符.该字段表示描述符在GDT中(在这种情况下,分割单元从gdtr寄存器获得GDT的基本线性地址)或在活动LDT中(在这种情况下,分割单元获得该基线性地址)来自ldtr寄存器的LDT).

2)从段选择器的索引字段计算段描述符的地址.索引字段乘以8(段描述符的大小),并将结果添加到gdtr或ldtr寄存器的内容中.

3)将逻辑地址的偏移量添加到段描述符的基本字段,从而获得线性(虚拟)地址.

现在,Pagging单元的工作是从虚拟地址转换物理地址.

参考:了解linux内核,第2章内存寻址


qst*_*ack 5

通常,每个发布的地址(对于x86架构)都是一个逻辑地址,该逻辑地址通过段表转换为线性地址。转换为线性地址后,然后通过页表将其转换为物理地址。
一篇不错的文章深入解释了这一点:http :
//duartes.org/gustavo/blog/post/memory-translation-and-segmentation/