先看一个奇怪的例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int val = 0; int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork\n");
return 0;
}
if(id == 0)
{
//child
//val = 100;
printf("child = %d,pid = %d,%p\n",val,getpid(),&val);
} else
else
{
//parent
sleep(3);
printf("parent = %d,pid = %d,%p\n",val,getpid(),&val);
}
sleep(1);
return 0;
}
输出的是:
在子进程中修改全局变量val的值为100之后输出:
地址没有变说明确实是同一块空间,但是值却完全不同???
这时因为C/C++语言所操作的地址都是虚拟存储技术产生的虚拟地址!都是假的!真正的物理地址是由操作系统管理的。
虚拟存储技术
当进程运行时,先将一部分装入内存中一部分暂留在磁盘中,当要执行的指令或数据不在内存中时由操作系统自动完成从磁盘中调入内存的工作就是虚拟存储技术。
每个进程的地址空间就是虚拟地址空间即分配给进程的虚拟内存。
虚拟存储技术就是一种资源转换技术,将CPU的时间和磁盘的空间换取昂贵的内存空间。
虚拟内存在哪里?
虚拟内存建立在存储体系(下图)之上,它一部分在内存一部分在磁盘中,将内存和磁盘有机的结合起来就得到了一个比物理内存大的多“内存”这就是虚存。
到底有多大?有计算机系统的寻址机制和磁盘可用空间大小的限制。如果为32位的计算机最大就有2^32即4G,64位的计算机最大就有2^64。
为什么要有虚拟存储技术?
除了可以得到一个更大的“内存”之外还有一个很重要的原因就是为了地址保护。
1.确保进程各自有独立的地址空间
2.确保进程访问合法的地址空间,防止地址越界。
3.确保进程的操作是合法的,防止访问越权。只读的就不可以进行写操作。
虚拟页式存储管理系统
基本思想:
进程运行之前并不装入所有的页面,而是装入一个页面或者不装入;之后根据程序运行的需要动态的装入其他页面;内存空间已满又需要装入其他新页面时根据某种算法置换内存中的某个页面。
具体方式:
请求调页——需要时装入页面
预先调页——预测哪个页面需要被调用,先加载到内存中。
由页表记录那些页面已将加载到内存中,哪些页面没有加载到内存中。
页表的大小:一个进程一个页表(可能很大),页表本身也是用页为单位储存的,一个储存单位是页表页;以为页表很大所以页表页的存放也不一定连续。为了找到不连续存放的页表页,引入了页目录。
地址转换过程
一个进程进入cpu时页目录的起始地址就会被推送到特定寄存器中(x86中的CR3),进程下CPU时就会被保存到PCB相关的现场信息中。
假设为32位的系统,页面大小为4K。虚拟地址就可被划分为页目录偏移、页表偏移、页内偏移。页目录起始位置和页目录偏移相结合就可以得到页目录中页表的位置,页表的位置和页表偏移结合就可以得到页框号位置,页框号和页内偏移结合就能找到真正的物理地址。