内存段和物理 RAM [关闭]

Posted

技术标签:

【中文标题】内存段和物理 RAM [关闭]【英文标题】:memory segments and physical RAM [closed] 【发布时间】:2015-04-01 10:23:55 【问题描述】:

进程的内存映射似乎被分割成段(堆栈、堆、bss、数据和文本),

我想知道这些段是否只是 过程的便利性和物理RAM只是一个线性阵列 地址或物理 RAM 是否也被分割成这些 细分市场? 此外,如果 RAM 没有分段并且只是一个线性阵列,那么如何 操作系统是否为进程提供这些段的抽象? 此外,如果到进程的内存映射只是一个线性数组而不是分段(MMU 将虚拟地址转换为物理地址),那么编程将如何变化?

【问题讨论】:

ad 3) 从 C(++) 程序员内存的角度来看确实显示为由内存管理器管理的线性数组,因此这部分对我来说没有意义。整个问题非常广泛,显示出很少的研究工作。检查类似的 Stack Overflow 问题,然后尝试缩小这一范围。 ***.com/….. @xmojmr 是的,它确实显示为一个线性数组,但它被分成多个段。 为什么投票结束?我不认为这个主题太广泛了。但绝对不是 C 题。我认为您应该删除该标签。 是的,但在 C(++) 中没有直接处理段的语言特性,因此编程不受影响。请参阅What is the advantage of using segment registers (today)? 和它的链接问题 @m0skit0 我添加了 C 是因为我是从 C 程序员的角度来询问的 【参考方案1】:

在支持虚拟内存的现代操作系统中,被划分为这些段的是进程的地址空间。在一般情况下,进程的地址空间以完全随机的方式投影到物理 RAM 上(具有一些固定的粒度,通常为 4K)。彼此相邻的地址空间页面不必投射到 RAM 的相邻物理页面中。 RAM 的物理页不必与进程的地址空间页保持相同的相对顺序。这一切都意味着在 RAM 中没有这样的分段,也不可能存在。

为了优化内存访问,操作系统可能(并且通常会)尝试将进程地址空间的连续页面映射到 RAM 中的连续页面,但这只是一种优化。在一般情况下,映射是不可预测的。最重要的是,RAM 由系统中的所有进程共享,属于不同进程的 RAM 页面在 RAM 中任意交错,这消除了在 RAM 中存在此类“段”的任何可能性。 RAM 中没有特定于进程的排序或分段。 RAM 只是虚拟内存机制的缓存。

同样,每个进程都使用自己的虚拟地址空间。这就是这些细分市场可以存在的地方。该进程无法直接访问 RAM。该进程甚至不需要知道 RAM 的存在。

【讨论】:

你能提供一个证据的参考吗? 证据?那是什么,刑事调查还是什么? :) @xmojmr 证据?你的意思是参考? @xmojmr:有什么可以描述虚拟内存的基础知识的吗?甚至***? 您是否尝试过查找virtual memory 的***条目?【参考方案2】:

这些段在很大程度上为程序加载器和操作系统提供了便利(尽管它们也提供了粗粒度保护的基础;执行权限可以限制为文本和禁止从rodata 写入)。1

物理内存地址空间可能是碎片化的,但不是为了这样的应用程序段。例如,在 NUMA 系统中,硬件使用特定位来指示哪个节点拥有给定的物理地址可能会很方便。

对于使用地址转换的系统,操作系统可以在某种程度上随意地将段放置在物理内存中。 (使用分段翻译,外部碎片可能是个问题;连续范围的物理内存地址可能不可用,需要昂贵的内存段移动。使用分页翻译,外部碎片是不可能的。分段的翻译的优点是需要较少的翻译信息:每个段只需要一个基址并与其他元数据绑定,而一个内存段通常有两个以上的页面,每个页面都有一个基址和元数据。)

如果没有地址转换,段的放置就必然不会那么随意。幸运的是,大多数程序并不关心段放置的具体地址。 (单地址空间操作系统

(请注意,可共享部分位于固定位置可能方便。对于代码,这可用于避免通过全局偏移表进行间接寻址,而无需在程序加载器/动态中进行二进制重写链接器。这也可以减少地址转换开销。)

应用程序级编程通常从这种分段中充分抽象出来,以至于它的存在并不明显。然而,纯粹的抽象对于物理资源使用的密集优化自然是不友好的,包括执行时间。

此外,编程系统可能会选择使用更复杂的数据放置方式(应用程序程序员无需了解实现细节)。例如,协同程序的使用可能会鼓励使用仙人掌/意大利面条堆栈,其中不期望连续性。类似地,垃圾收集运行时可能会提供地址空间的额外划分,不仅用于托儿所,还用于将没有对可收集内存的引用的叶对象与非叶对象分离(减少标记/清除的开销)。提供两个堆栈段也不是特别罕见,一个用于地址未被占用(或至少是固定大小)的数据,另一个用于其他数据。


1在类 Unix 操作系统的平面虚拟地址空间中这些段的传统布局(具有向下增长的堆栈)将文本放置在最低地址,rodata紧接其上方,紧接其上方的初始化数据,紧接其上方的零初始化数据(bss),堆从bss的顶部向上增长,堆栈从应用程序的虚拟地址空间部分的顶部向下增长。

堆和堆栈相互向着增长允许任意增长(对于使用该地址空间的单个线程!)。这种布局还允许程序加载器简单地将程序文件从最低地址开始复制到内存中,按权限对内存进行分组,有时可以允许单个全局指针寻址所有全局/静态数据范围(rodata、data 和bss)。

【讨论】:

【参考方案3】:

进程的内存映射看起来是分段的(堆栈、堆、bss、数据和文本)

这是 Unix 使用的基本映射;其他操作系统使用不同的方案。不过,一般来说,它们会将进程内存空间分成单独的段,用于执行代码、堆栈、数据和堆数据。

我想知道这些段是否只是为了方便而对进程进行抽象,而物理 RAM 只是地址的线性数组,还是物理 RAM 也被分割成这些段?

视情况而定。 是的,这些段是由操作系统创建和管理的,以利于流程。但是物理内存可以安排为线性地址、存储段或不连续的 RAM 块。由操作系统管理整个系统内存空间,以便每个进程都可以访问它自己的一部分。

虚拟内存增加了另一层抽象,因此看起来像线性内存位置的东西实际上映射到 RAM 的单独页面,这些页面可能位于物理地址空间中的任何位置。

另外,如果 RAM 不是碎片化的并且只是一个线性数组,那么操作系统如何为进程提供这些段的抽象?

操作系统通过使用虚拟内存映射硬件来管理所有这些。每个进程看到其代码、数据、堆栈和堆段的连续内存区域。但实际上,操作系统将每个段中的页面映射到 RAM 的物理页面。因此,两个相同的运行进程会看到由连续内存段组成的相同虚拟地址空间,但组成这些段的内存页面将映射到完全不同的物理 RAM 页面。

但请记住,物理 RAM 实际上可能不是一个连续的内存块,但实际上可能被拆分为多个不相邻的块或内存库。由操作系统以对进程透明的方式管理所有这些。

如果进程的内存映射看起来像一个线性数组而不是分段,那么编程将如何改变?然后 MMU 会将这些虚拟地址转换为物理地址。

MMU 始终以这种方式运行,将虚拟内存地址转换为物理内存地址。操作系统为每个进程建立和管理每个段的每个页面的映射。例如,每次进程超出其堆栈分配时,操作系统会捕获段错误并将另一个页面添加到进程的堆栈段,将虚拟页面映射到从可用内存中选择的物理页面。

虚拟内存还允许操作系统将进程页面临时换出到磁盘,这样所有正在运行的进程所占用的虚拟内存总量很容易超过系统的实际物理内存 RAM 空间。只有当前活动的执行进程才能真正访问真实的物理 RAM 页面。

【讨论】:

【参考方案4】:

我想知道这些段是否只是对 为方便起见,物理 RAM 只是一个线性数组 地址或物理 RAM 也被分成这些段?

这实际上高度依赖于架构。有些会有硬件工具(例如 x86 的描述符寄存器)来将 RAM 分割成段。其他人只是将此信息保存在软件中(此过程的操作系统内核信息)。此外,一些段信息与执行完全无关,它们仅用于代码/数据加载(例如重定位段)。

另外,如果 RAM 没有碎片化并且只是一个线性数组,那么如何 操作系统为进程提供这些段的抽象吗?

进程代码从不引用段,他只知道地址,所以操作系统没有什么要抽象的。

如果内存映射到进程,编程将如何变化 会显示为一个线性阵列而不是分割成段吗? 然后 MMU 会将这些虚拟地址转换为 物理的

编程不会受到影响。当您在 C 中编程时,您不会定义任何这些段,并且代码也不会引用这些段。这些段是为了保持有序的布局,甚至不需要跨操作系统相同。

【讨论】:

以上是关于内存段和物理 RAM [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

内存

STM32 内存分配解析及变量的存储位置

内存映射显示的 RAM 多于物理可用的 RAM

操作系统----内存管理

linux下内存

[转]io端口和io内存