Linux程序地址空间

版权声明:Oce2ns的大板 https://blog.csdn.net/weixin_39392653/article/details/84201922
  • 概述

程序地址空间,如果更加好理解的说,应该叫进程地址空间。因为程序是一些死代码,他们并非在内存上,而是安安静静的躺在硬盘上,只有执行程序,变成进程时才有内存的进程地址空间。
  • 先上一个内存的空间布局图

在这里插入图片描述

这感觉也没什么,就是内存的分布图,但是我们再把进程引入进来。观察一下。
#include <stdio.h> 
#include <unistd.h>
 int val = 100;//先定义一个全局变量
 int main()
 {
      int pid = fork();//穿件一个变量pid记录fork函数的返回值
      if(pid<0)
     {
          return -1;
     }
     else
     {
         if(pid == 0)//为子进程
         {
             val = 200;//修改val的值为200
             printf("child val:%d----%p\n",val);
         }
         else//返回值为子进程的pid
         {
             sleep(1);
             printf("parent val:%d----%p\n",val);
         }
     }
         return 0;
 }
我们期待的结果是,val的值修改为200,然后打印了子进程,然后打印了父进程。可是我们得到的却是

在这里插入图片描述

这也好理解,先有的是父进程,再有子进程。但是我们再加一点进去,在打印后面取出父子进程的val值得地址看看。

在这里插入图片描述

这就尴尬了,按理说,父子进程代码共享,数据独立,父100,子200.两块空间。那为什么,打印地址却是一样的呢?只能说明,操作系统给我们展示的是一个假地址。假地址只是对内存的一块编号,编号的开始就是0x00000000,结束是0xFFFFFFFF。是一个虚拟的地址,而不是一个真正的物理地址。每一个进程都有自己的遗传编号,在往深的想。32位平台,最大支持4G内存(当然后来新的技术可以扩,我们先不说)而实际你可以看到,每一个运行中的程序(进程)的内存都是4G,这是什么意思啊,都4G,几十个进程一块运行?那就说明,操作系统为每一个进程都开辟一块虚拟内存空间。我们再c和c++中看到的都是一些虚拟地址空间。而OS的任务就是负责将虚拟内存转换为实际的物理内存。画个图
进程pcb其实就是一个结构体,也就是task_struct。里面成员有标识符,状态,优先级,程序计数器,内存指针,上下文数据,I/O状态信息等等。而虚拟地址其实也是一个结构体,mm _struct。这个结构体里有一个字段max_size,min_size就记录了地址的最大值,最小值。另外每一个地址在内存中都有一条类似三八线一样的划分。比如code_start,code_end,这个区域里就是代码存放的位置。什么data_start,data_end,记录存数据的地址位置。
那么虚拟地址怎么去访问真实的物理地址呢?就用到页表,其实也是个结构。这个表里就记录了虚拟地址和物理地址的转换关系。通过虚拟地址访问物理地址时,就用页表建立一个关系。最后就访问到物理地址了。页表还具有内存访问控制的限制。(代码段只读),就是页表的限制。因为页表还要记录要访问的这块地址的属性。
我们访问的是一个连续的虚拟地址。但是在实际的物理内存里,并不是连续的。只是为了进程的执行,才虚拟连续的地址。
操作系统创建一个进程以后,内存指针,就指向了这个进程的虚拟内存地址。
这里有一个问题,就是父子进程创建时,数据区域指向同一个区域,如果给子进程的数据开辟区域,但是不用,那就是一种浪费。而不开辟,但是如果需要修改子进程的数据时,就得在父子进程指向相同位置的数据进行改动,这是不能够的,因为这样就会造成父进程的数据丢失。所以引入了写时拷贝技术。但是在说这个之前,我们得先说到两种进程创建的函数。fork()和vfork()。

vfork()

vfork创建子进程后,父子进程是共用一块虚拟地址空间那么他们共用同一个栈区,有可能会造成调用栈混乱。所以Vfork设计出来的目的就是为了创建一个子进程,然后直接运行其他的程序。重新运行其他程序就是重新给子进程开辟新的空间,更新他自己的一份地址空间和页表。自从fork函数使用了写时拷贝技术以后,这个函数就淘汰了。

fork()

fork函数采用了写时拷贝的技术,一开始,他俩因为完全拷贝,所以数据指向同一块物理空间,当父子进程有一方修改数据以后,就会重新分配空间,提高效率。

猜你喜欢

转载自blog.csdn.net/weixin_39392653/article/details/84201922