Linux概念——进程地址空间

<1> 进程地址空间

对于C语言学习,我们并不陌生这张图
在这里插入图片描述
我们编写一段C语言代码来验证上述图的准确性

#include<stdio.h>
#include<stdlib.h>

int g_val = 100;
int g_unval;

int main(int argc, char* argv[], char* env[])
{
    
    
  //环境变量
  printf("env addr:%p\n", env[0]);
  printf("env addr:%p\n",env[1]);
  //命令行参数
  printf("argv addr:%p\n",argv[0]);
  printf("argv addr:%p\n",argv[argc-1]);
  char* mem = (char *)malloc(sizeof(char)*4);

  //栈
  printf("Stack addr:%p\n",&mem);
  //堆
  printf("Heap addr:%p\n",&mem);
  //未初始化数据
  printf("uninit addr:%p\n",&g_unval);
  //初始化数据
  printf("init addr:%p\n",&g_val);
  //正文代码
  printf("code addr:%p\n",&main);

  return 0;
}

结果

在这里插入图片描述
可以看到对于程序中定义的变量打印出来的地址全部都一一对应了

Q1:什么是地址空间?

地址空间是对物理内存的一种虚拟化表示,在Linux内核中以结构体的形式划分为不同的区域。

<2> 虚拟地址空间

既然前面说到了进程空间是一种虚拟化表示,我们运行下面代码来验证进程地址空间

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
    
    
  pid_t id = fork();
  if(id < 0)
  {
    
    
    perror("fork");
    return 0;

  }
  else if(id == 0)
  {
    
     //child 
     printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
  }
  else
  {
    
     //parent
    printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
  }
  sleep(1);
  return 0;
}

在这里插入图片描述
由结果可以看出,父进程的全局变量地址和子进程的全局变量地址相同,正好对应了进程空间地址那张图,那么我们稍作修改

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
    
    
  pid_t id = fork();
  if(id < 0)
  {
    
    
    perror("fork");
    return 0;

  }
  else if(id == 0)
  {
    
     //child ,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
    g_val = 100;
    printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
  }
  else
  {
    
     //parent
    sleep(3);
    printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
  }
  sleep(1);
  return 0;
}

在这里插入图片描述
我们发现,父子进程,输出地址是一致的,但是变量内容不一样

能得出如下结论:

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
  • 但地址值是一样的,说明该地址绝对不是物理地址
  • 在Linux地址下,这种地址叫做虚拟地址
  • 我们在用C/C++语言所看到的地址,全部都是虚拟地址物理地址,用户一概看不到,由OS统一管理

Q2:为什么要有地址空间?

  1. 如果没有地址空间,那么进程访问的地址都是物理地址,当一个进程的指针去读写另一个进程的地址时,出现野指针现象,导致别人的空间遭到破坏,从而违背了进程的独立性原则。
  2. 进程数据存放的位置时不连续的,因此访问难度较大,也增加了异常越界的概率。

Q3: 地址空间时怎么工作的?

  1. 既然地址空间时虚拟的,那么OS必须负责将 虚拟地址 转化成 物理地址 , 这中间就需要建立映射关系——页表来进行转换。
  2. 由操作系统去访问物理内存,人为干扰的进程非法行为将被禁止,堆内存起到了保护作用。

<3> 页表

在这里插入图片描述
上面的图就足矣说名问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址!

扫描二维码关注公众号,回复: 12867970 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_40076022/article/details/114544984