进程地址空间(PAS)

"进程地址空间" = "虚拟地址空间" = "地址空间";

"进程内存" ≠ "虚拟内存";

32位系统虚拟地址空间为4GB,一般使用不完,用户和内核都使用不完;

前言:一个程序要执行,我们可以让他独享偌大的内存,它执行完了,再执行第二个程序....以此类推,总之,我们CPU找谁,我们就调谁进内存,但是存在两个问题:第一,一般程序没有那么大,实在是浪费硬件资源;第二:两个程序在硬盘与内存之间的切换实在是浪费时间,特别是磁盘,速度明显慢于内存;

我们可以让每个程序占用物理内存的一部分,我们划分好区域,但是存在安全问题:程序A对于B程序占用的空间由于运行错误,进行了错误的写操作,导致B程序运行错误。

那么现代OS是怎么做的?加了一层抽象:虚拟内存;

MMU(内存管理单元)负责虚拟地址->物理地址;

TLB则是为了加速翻译;

总之,有了它们俩,CPU可以通过虚拟地址找到物理地址;

其实我们平常代码中%p打印出来的这些全都是虚拟地址:

#include<unistd.h>
#include<iostream>

int global = 0;
int main()
{
  pid_t id = fork();
  if(id==0)
  {
    global = 190;
    std::cout<<"Child-> "<<&id<<" "<<&global<<" "<<global<<std::endl;
  }
  else{
    std::cout<<"father-> "<<&id<<" "<<&global<<" "<<global<<std::endl;
  }
  return 0;
}

 执行结果:

father-> 0x7fff33094fec 0x601194 0
Child-> 0x7fff33094fec 0x601194 190

 我们可以看到全局变量global初始值为0,父进程调用fork();系统调用创建子进程后,子进程对global做出了改变,打印出来确实也变了,但是地址竟然是一样的,同一块内存(如果是物理内存的话)不可能存在两种值;所以这个打印出来的地址是“假的”地址,是一种假象;

正是虚拟内存让程序各自拥有一个独立的空间(如下): 

 你的代码中的值根据其属性,存在不同区域,OS会建立上图这个进程地址空间和物理内存之间的一个映射;对于global这个变量,虚拟地址映射的其实是同一块物理地址,如果你仅仅是去读取global的值,它们找的是同一个地方,但如果子进程要对这个区域执行写操作,就会触发一个缺页异常,然后OS会拷贝这个区域并重新建立新的映射,然后恢复执行你的代码去修改它,这样也有好处:如果你不写的话,两份代码共用了内存,节省了空间;

每一个进程都有自己的虚拟地址空间,映射到物理内存;

每个进程都有自己的进程控制块(在Linux源码中是一个struct task_struct{};),用于OS更好地管理每个进程,它里面有一个mm_struct{};如下,它将虚拟内存分割为了我们上面图中的几块区域;而OS的页表建立起了它与物理内存之间的联系;

(图片来自:链接

内存之后就是磁盘,这又涉及到换入和换出,分页分段....

我觉得我还是没有理解:virtual memory vs process address space .

大家可以看一下这个:链接

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值