在硬件工程师和普通用户眼中,内存就是插入或固化在主板上的记忆棒,具有一定的容量,比如64MB。但是在应用程序员的眼里,他们不太在意主板上插入的内存量,而是他们可以使用的内存空间——他们可以开发一个占用1GB内存的程序,让它在上面运行操作系统平台。即使这个正在运行的主机上只有 128 MB 的物理内存。对于操作系统开发人员来说,它介于两者之间。他们需要了解物理内存的细节,还需要提供一种机制,为应用程序程序员提供另一个内存空间。这个内存空间的大小可以和实际物理内存大小没有关系。

我们将主板上物理内存条提供的内存空间定义为物理内存空间;将应用程序员看到的内存空间定义为线性空间。物理内存空间的大小在不同的主机上可能会有所不同,并随着主板上插入的物理内存模块的容量而变化;但是为应用程序程序员提供的线性空间是固定的,并且不会随物理内存的变化而变化。更改以确保应用程序的可移植性。虽然物理内存的大小会影响应用程序的性能,并且在很多情况下对物理内存的大小有最低要求,但这些因素只是为了让操作系统能够正常运行。
线性空间的大小在32位平台上是固定的4GB大小,每个进程都是一样的(一个应用程序可以是多进程的,在OS的眼中,它是基于处理单元)。也就是说,线性空间不是进程共享的,而是进程隔离的。每个进程都有相同的 4 GB 线性空间。进程对某个内存地址的访问将永远不会与其他进程对同一内存地址的访问发生冲突。例如,一个进程读取线性空间地址1234ABCDh可以读取整数8,而另一个进程读取线性空间地址1234ABCDh可以读取整数20,这取决于进程本身的逻辑。

在任何时候,只有一个进程在一个 CPU 上运行。所以对于这个CPU,此时此刻整个系统中只有一个线性空间,而这个线性空间就是面向这个进程的。当进程切换时,线性空间也随之切换。所以结论是每个进程都有自己的线性空间,只有当这个进程在运行时,它的线性空间才被运行它的CPU知道。在其他时候,它的线性空间对 CPU 是不可知的。所以虽然每个进程可以有4GB的线性空间,但在CPU眼中,只有一个线性空间。线性空间随着进程切换而变化。
虽然线性空间的大小和物理内存的大小没有关系,但使用线性空间的应用程序最终会在物理内存中运行。应用程序给出的任何线性地址最终都必须转换为物理地址才能真正访问物理内存。因此,线性内存空间必须映射到物理内存空间,而这种映射关系需要使用硬件架构规定的数据结构来建立。我们不妨先称它为映射表。映射表的内容是某个线性内存空间与物理内存空间的映射关系。 OS Kernel一旦告诉CPU映射表的位置,当CPU需要访问线性空间地址时,它会根据映射表的内容将线性空间地址转换为物理空间地址,然后再转换物理地址发送到地址线,毕竟地址线只知道物理地址。
所以,我们很容易得出一个结论,如果我们给出不同的映射表,那么CPU转换某个线性空间地址的物理地址也会不同。因此,我们为每个进程创建一个映射表,并根据自己的需要将每个进程的线性空间映射到物理空间。由于某个时间在某个CPU上只能运行一个应用程序,当任务切换时,映射表也被替换为对应的映射表,实现每个进程有自己的线性空间,而不是相互之间。影响。因此,任何时候对于一个CPU来说,只需要一张映射表就可以实现当前进程的线性空间到物理空间的转换。

2. 操作系统内核空间和进程空间
由于OS Kernel必须随时存在于内存中,但进程是可以切换的,因此内存中随时存在OS Kernel和用户进程两部分。在任何时候,一个CPU都只有一个线性空间,所以这个线性空间必须分为两部分,一部分用于OS Kernel,另一部分用于用户进程。由于OS Kernel一直都占用部分线性空间,它们留给OS Kernel的线性空间对于所有进程的线性空间可以完全相同,即在它们各自的映射表中,也被分为两部分,一是进程私有映射部分,与OS Kernel映射部分内容完全一致。
从这个意义上讲,我们可以认为对于所有进程来说,它们共享OS Kernel所占用的线性空间,每个进程都有自己私有的线性空间。如果我们将任意 4GB 线性空间划分为 1GB 的 OS Kernel 空间和 3GB 的进程空间,那么所有进程的 4GB 线性空间中的 1GB OS Kernel 空间是共享的,剩下的 3GB 进程空间为每个进程都是私有的。 Linux 会这样做,而 Windows NT 允许操作系统内核和进程各自使用 2 GB 的线性空间。

3. 段映射和页面映射
线性空间的所有内容只有放在物理内存中才能真正被执行和操作。因此,虽然 OS Kernel 和进程被放置性空间中,但它们最终必须放置在物理内存中。因此,OS Kernel 和所有进程最终共享物理内存。现阶段物理内存远远小于线性空间——线性空间为4GB,而物理内存空间往往只有几百兆甚至更少。另外,即使物理内存有4GB,由于每个进程可以有3GB的线性空间(如果进程私有线性空间是3GB),如果把所有进程的线性空间内容都放在物理内存中,显然不现实。因此,OS Kernel 必须将某些进程暂时不使用的数据或代码存储在物理内存之外,并为当前最需要它的进程提供有限的内存。另外,由于 OS Kernel 可能随时运行,因此 OS Kernel 最好永远保存在物理内存中。我们只交换进出过程数据。
所以,使用变长段映射的结果是一个段要么全部换入,要么全部换出。但在现实中,并不是一个程序中的所有代码和数据都可以被频繁访问,往往只能访问全部代码数据的一部分,甚至一小部分。因此,更有效的策略是只换掉不常用的部分,保留常用的部分。而不是换入和换出整个段。这样可以避免大块的慢速磁盘操作。
这是定长映射策略。我们将内存空间划分为定长块,每个定长块称为一个页。映射表的基本格式为(物理空间页面的起始地址)。由于页面是定长的,所以不需要指明它的长度。另外,我们不需要在映射表中指定线性地址,我们可以使用线性地址作为索引,来检索映射表中对应的物理地址。使用页面时的策略是:换出时,只换出那些不活跃的,也就是不经常使用的页面,保留那些活跃的页面。换入时,只换入请求访问的页面,不请求访问的页面永远不会交换到物理内存中。这就是Demand Page算法的核心思想。
这就导致了页大小的问题:首先,我们不能以字节为单位,这样映射表的大小和线性空间的大小是一样的——如果整个线性空间都被映射了- 我们不能让所有的线性空间都用来存储这个映射表。由此我们也可以知道,页面越小,映射表的容量就越大。而且我们不能让映射表占用太多空间。但是如果页面太大,就会面临和不定长段映射一样的问题。每次换出一个页面,都需要进行大量的磁盘操作。另外,由于进程分配内存的最小单位是页,如果我们的页大小是4MB,那么即使一个进程只需要4KB内存,也得占用整个4MB页。这显然是非常大的浪费。所以我们必须在两者之间做出妥协。一般平台指定的页面大小为1KB到8KB,IA-32指定的页面大小为4KB。 (IA-32也支持4MB页面,可以根据自己操作系统的用途选择,一般使用4KB页面)。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-379045-1.html
郑秀晶美炸了
@CYAdol
特别申明
我们不针对美国