首先我们先来看一段代码
我们定义一个变量a并且初始化成0,下来我们fork()一个进程,在其中改变a的值,然后将变量a的值和地址打印出来。
看结果:
我们可以看到,子进程和父进程a的值不一样,但是地址却是一样的,这是怎么回事呢?相同的地址怎么可能存的值不一样呢?打印出不同的两个数a,这就说明操作系统中存了两个变量a,但是地址我们打印出来的地址是一个又是怎么回事呢?这就可以间接引出,虚拟内存和物理内存。
- 虚拟内存
首先我们都知道每个进程都有自己独立的4G内存空间,各个进程的内存空间具有类似的结构。
当一个进程创建时,将会建立起自己的内存空间,进程的数据,代码之类的从磁盘拷贝到自己的进程空间中,至于哪些数据在哪里,都由进程控制表中的task_struct来记录着。
并且每个进程分配的内存空间都对应着相应的磁盘空间。
那么每个进程都有自己独立的4G内存空间,那么当我们创建很多很多进程,那岂不是需要n*4G的内存空间,我们的手里的计算机很明显是没有那么多内存的,这时就需要引入一个词‘映射’。
1)每个进程的4G内存空间只是虚拟内存空间,每次访问内存空间的某个地址,都需要把地址翻译为实际物理内存地址
。
2)所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物理内存上。
3) 进程要知道哪些内存地址上的数据在物理内存上,哪些不在,还有在物理内存上的哪里,需要用页表来记录
。
4)页表的每一个表项分两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存页的地址(如果在的话)
。
5)当进程访问某个虚拟地址,去看页表,如果发现对应的数据不在物理内存中,则缺页异常
。
6)缺页异常的处理过程,就是把进程需要的数据从磁盘上拷贝到物理内存中,如果内存已经满了,没有空地方了,那就找一个页覆盖,当然如果被覆盖的页曾经被修改过,需要将此页写回磁盘
。