前言
现现机器提供的物理内存(physical memory)模型非常简单。内存就是一个字节数组。要读取(read)内存,必须指定一个地址(address),才能访问存储在那里的数据。要写入(write)或更新(update)内存,还必须指定要写入给定地址的数据。
程序运行时,一直要访问内存。程序将所有数据结构保存在内存中,甚通过各种指令来访问它们,例如加载和保存,或利用其他明确的指令,在工作时访问内存。不要忘记,程序的每个指令都在内存中,因此每一读取指令都会访问内存。
一、访问内存的程序
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
int main(int argc, char *argv[])
{
int *p = malloc(sizeof(int)); // a1
assert(p != NULL);
printf("(%d) memory address of p: %08x\n", getpid(), (unsigned) p); // a2
*p = 0; // a3
while (1)
{
Spin(1);
*p = *p + 1;
printf("(%d) p: %d\n", getpid(), *p); // a4
}
return 0;
}
该程序做了几件事。首先,它分配了一些内存(a1 行)。然后,打印出内存(a2)的地址,然后将数字 0 放入新分配的内存(a3)的第一个空位中。最后,程序循环,延迟一秒钟递增 p 中保存的地址值。在每个打印语句中,它还会打印出所谓的正在运行程序的进程标识符(PID)。该 PID 对每个运行进程是唯一的。
二、运行单个程序
prompt> ./mem
(2134) memory address of p: 00200000
(2134) p: 1
(2134) p: 2
(2134) p: 3
(2134) p: 4
(2134) p: 5
ˆC
二、运行多个程序
prompt> ./mem &; ./mem &
[1] 24113
[2] 24114
(24113) memory address of p: 00200000
(24114) memory address of p: 00200000
(24113) p: 1
(24114) p: 1
(24114) p: 2
(24113) p: 2
(24113) p: 3
(24114) p: 3
(24113) p: 4
(24114) p: 4
从示例中看到,每个正在运行的程序都在相同的地址(00200000)处分配了内存,但每个似乎都独立更新了 00200000 处的值!就好像每个正在运行的程序都有自己的私有内存,而不是与其他正在运行的程序共享相同的物理内存。
总结
这正是操作系统虚拟化内存(virtualizing memory)时发生的情况。每个进程访问自己的私有虚拟地址空间(virtual address space)(有时称为地址空间,address space),操作系统以某种方式映射到机器的物理内存上。一个正在运行的程序中的内存引用不会影响其他进程(或操作系统本身)的地址空间。对于正在运行的程序,它完全拥有自己的物理内存。但实际情况是,物理内存是由操作系统管理的共享资源。