程序地址空间--Linux

文章目录

  • 01. 研究背景
  • 02. 程序地址空间分布
    • 1)空间布局图
    • 2)上段代码,来感受一下。
    • 3)写时拷贝
  • 03. 进程地址空间
    • 分页&虚拟地址空间
    • 扩展--只做本章了解。

01. 研究背景

  • ernel 2.6.32
  • 32位平台

02. 程序地址空间分布

1)空间布局图

在我们学习c语言的时候我们都接触过下面这张空间布局图。

程序地址空间--Linux_第1张图片

可是我们对他并不理解!

2)上段代码,来感受一下。

#include
#include

int a=1, b; 
int main(int argc, char* argv[], char* env[])
{
  printf("code addr:%p\n", main);
  
  printf("uninit global addr:%p\n", &b);
  printf("init global addr:%p\n", &a);

  char* heap_men = (char*)malloc(10);
  printf("heap addr:%p\n", heap_men);
  printf("stack addr:%p\n", &heap_men);

  int j=0;
  for( j=0; j<argc; ++j)
  {
    printf("argv[%d] addr:%p\n", j, argv[j]);
  }

  for(j=0; env[j]; ++j)
  {
    printf("env[%d] addr:%p\n", j, env[j]);
  }

  return 0;
}

有程序可知空间布局图,的确如此分布;共享区不好演示,此处就不演示了。
程序地址空间--Linux_第2张图片

3)写时拷贝

我们了解了以上内容。我们来看看下面一段代码。

#include 
#include 
#include 
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_第3张图片
通过上面我们明显发现输出结果

  • //与环境相关,观察现象即可

      child[15090]: 100 : 0x601058
      parent[15089]: 0 : 0x601058
    

我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:

  1. 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
  2. 但地址值是一样的,说明,该地址绝对不是物理地址!
  3. 在Linux地址下,这种地址叫做 虚拟地址
  4. 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理OS必须负责将 虚拟地址 转化成 物理地址。

提醒:
3. 写时拷贝我们这里粗讲,以后文章会详细介绍;现在我们只需了解就可以了。
2. 写时拷贝:我们知道子进程是父进程的一份拷贝;由此父子进程的虚拟地址也是相同的。刚开始的时候两者虚拟地址映射同一块物理内存,当子进程的变量值发生改变的时候,就会立即开辟一块新的空间给子进程。此时两者虚拟地址虽然相同,但映射到实际的物理空间内存就不同了。

03. 进程地址空间

  • 所以之前说‘程序的地址空间’是不准确的,准确的应该说成 进程地址空间 ,那该如何理解呢?看图!!!

分页&虚拟地址空间

程序地址空间--Linux_第4张图片

  • 说明:
    • 上面的图就足矣说名问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址!

扩展–只做本章了解。

程序地址空间--Linux_第5张图片
提醒:

 函数调用实际是通过虚拟地址调用的。
 可执行程序其实编译的时候,内部已经有地址。
 地址空间不止是OS内部要遵守,其实编译器也要遵守。
 每一个函数和变量都有地址。

我们使用Linux的时候,我们写的test.c文件会通过
gcc -o mytest test.c这条指令生成mytest可执行文件.exe。
通过编译器;
此时mytest里面同样有内存,而且是虚拟地址;CPU调用的也是虚拟地址。CPU读到指令内部,使用的地址是虚拟地址,再通过映射找到物理地址。

.
.
.
感觉有所收获的话,友友们给小丁一个赞

你可能感兴趣的:(Linux,linux)