当前位置:   article > 正文

进程地址空间详解

进程地址空间

 进程地址空间是用来描述操作系统中的进程所占的空间,因为进程的独立性,所以通过让每个进程都看到完整的地址空间。其本质是虚拟地址空间,通过虚拟地址与物理地址的映射来分配空间。

这段空间中自下而上,地址是增长的,栈是向地址减小方向增长(栈是先使用高地址),而堆是向地址增长方向增长(堆是先使用低地址),堆栈之间的共享区,主要用来加载动态库

1、进程地址空间不是内存

2、进程地址空间,会在进程的整个生命周期内一直存在,直到进程退出

这也就解释了全局变量为什么会一直存在,原因是未初始化数据,初始化数据,这些区域是一直存在的,不同于栈区需要维护栈帧,堆区需要向系统申请,静态区和常量区的变量,常量和函数定义好了以后就直接存储在相应区域。

 进程地址空间究竟是什么?

我们通过一个代码来看一个现象,我们定义了一个全局变量,fork创建一个子进程,让父进程和子进程完成自己的任务,在子进程中定义count来计数,当子进程的打印任务进行到第五次时,让子进程将这个全局变量改成100:

  1. #include<stdio.h>
  2. #include<unistd.h>
  3. int g_val = 0;
  4. int main()
  5. {
  6. printf("begin.....%d\n",g_val);
  7. pid_t id = fork();
  8. if(id==0)
  9. {
  10. //child
  11. int count = 0;
  12. while(1)
  13. {
  14. printf("child: pid: %d,ppid: %d, g_val:%d, &g_val: %p\n",getpid(),getppid(),g_val,&g_val);
  15. sleep(1);
  16. count++;
  17. if(count == 5)
  18. {
  19. g_val = 100;
  20. }
  21. }
  22. }
  23. else if(id>0)
  24. {
  25. //father
  26. while(1)
  27. {
  28. printf("father: pod: %d,ppid: %d, g_val:%d, &g_val: %p\n",getpid(),getppid(),g_val,&g_val);
  29. sleep(1);
  30. }
  31. }
  32. else
  33. {
  34. //todo
  35. }
  36. return 0;
  37. }

代码共享,所以看到前五次打印的g_val的地址都是一样的,这我们不意外,等到了第六次时,我们发现父进程g_val依然是0,子进程的g_val变成了100,因为我们将它改了,这也不意外,因为前面说了,父子进程之间代码共享,而数据是各自私有一份的(写时拷贝),但是令人奇怪的是地址竟然是一样的!

如果是物理地址绝对不可能出现这种情况,所以它应该是虚拟地址,应该也是通过映射的方式来实现的,进程地址空间中的地址应该是一些虚拟地址。

进程地址空间本质是进程看待内存的方式,抽象出来的一个概念,内核:struct mm_struct,这样的每个进程,都认为自己独占系统内存资源,实际上是操作系统通过对物理地址分段,分配给不同的进程,但是对于进程而言,看到整个资源全在自己手上,体现了进程的独立性,要实现这种形式,我们就需要在进程和内存硬件之间加一层来实现,这一层就是“页表”

 什么是页表呢?

通过上述,我们可以知道要想实现,那就需要建立虚拟地址到物理地址的映射,页表就是这样一张实现虚拟地址到物理地址的映射表,每个进程都有一张,这样进程就在可以都看到同一份资源的情况下随意使用地址,即使虚拟地址相同,但是其映射的物理地址不同。

操作系统是软硬件资源的管理者,我们不能越过操作系统去直接访问硬件,这是为了避免风险。

需要详细了解可以看一下下边的文章:

 http://t.csdnimg.cn/gip0j

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/769998
推荐阅读
相关标签
  

闽ICP备14008679号