【LINUX】进程地址空间

文章目录

  • 前言
  • 程序地址空间
    • 为什么要有程序地址空间
    • malloc的本质
    • 深入理解地址空间
  • 结语

前言

我们先运行一段程序,可以看到我们创建了一个子进程,并且父进程和子进程都对val进行了修改。

int main()
{
  int val = 10;
  pid_t id = fork();

  if(id == 0)
  {
    val = 20;
    printf("child pid : %d,ppid : %d,val : %d,&val: %p \n",getpid(),getppid(),val,&val);
  }
  else
  {
    val = 30;
    printf("parent pid : %d,ppid : %d,val : %d,&val : %p \n",getpid(),getppid(),val,&val);
  }
}

看一下运行结果:
在这里插入图片描述
非常神奇的是,同一个地址,竟然对应两个不同的值,这其实就与我们的程序地址空间有关。

程序地址空间

我们知道,一个地址只能对应一个值,而上面的结果则证明:我们使用C/C++语言拿到的地址并不是真正的物理地址,而是 虚拟地址,对于用户来说是看不到真实物理地址的由OS帮助我们维护。


代码区,堆区,静态区,这样的区域应该如何理解?

进程地址空间,本质就是一个内核数据结构。

【LINUX】进程地址空间_第1张图片

为什么要有程序地址空间

数据和代码只能存在真正的内存中,既然我们使用的是虚拟地址,那我们要如何通过虚拟地址找到真正的物理地址才行,实际上,是通过页表来实现的。
【LINUX】进程地址空间_第2张图片
父进程在创建子进程的时候,会再次新建一个进程,新进程会继承父进程的地址空间等信息,如果子进程不对数据进行修改,即只读,则父子进程共享同一个数据,但如果子进程发生了更改数据等操作,会再去开辟一块空间,我们称为:写时拷贝。


回到我们的问题,为什么要有这样的程序地址空间呢?

1.防止地址随意访问,保护物理内存与其他进程。
2.将进程管理和内存管理解耦合(页表)。
3.可以让进程以统一的视角,看待自己的代码和数据。

malloc的本质

向操作系统申请内存的时候,操作系统并不会立即给你,而是等你需要的时候才给你,这种方式被称为缺页中断,因为操作系统不允许任何的 浪费 和 不高效
【LINUX】进程地址空间_第3张图片
在申请完成空间后使用之前,程序就有一段小小的时间窗口,这个时间没有被正常使用,但是别人使用不了,被称为闲置状态

深入理解地址空间

我们的程序在编译的时候,没有被加载到内存,那么我们的程序有没有地址呢?

当然是有的,不仅操作系统要遵守虚拟地址的规则,我们的编译器同样要遵守这样的规则。源代码在被编译的时候,就是按照虚拟地址空间的方式进行对代码和数据早就编好了对应的编制。

程序携带着写好的虚拟地址被加载到内存里,当进程从入口函数main里拿到第一条命令的时候,会让cpu执行这条命令,cpu执行命令时,会去正文代码里找对应的虚拟地址,再通过页表的映射找到物理地址,然后在物理地址处拿到下一个命令,重复这个过程。

画图理解一下:
【LINUX】进程地址空间_第4张图片

结语

到这里,本篇文章就结束了,希望对你有所帮助,我们下次再见。

你可能感兴趣的:(LINUX,linux,c++,运维)