【Linux】程序地址空间

程序地址空间

首先引入地址空间的作用

cpp 复制代码
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 

	int g_val = 100;
  6 int main()
  7 {
  8   pid_t id = fork();
  9   if(id == 0)
 10   {
 11     int cnt = 0;
 12     while(1)
 13     {
 14       printf("I am child,pid : %d,ppid : %d,g_val : %d,&g_val : %p\n",getpid(),getppid(),g_val,&g_val);
 15       cnt++;
 16       sleep(1);
 17       if(cnt == 5)
 18       {
 19         g_val = 200;
 20         printf("child chage g_val 100 -> 200 success\n");
 21       }
 22     }
 23   }
 24   else 
 25   {
 26     //father
 27     while(1)
 28     {                                                                                                                                                
 29 
 30       printf("I am father,pid : %d,ppid : %d,g_val : %d,&g_val : %p\n",getpid(),getppid(),g_val,&g_val);
 31       sleep(1);
 32     }
 33   }
 34   return 0;
 35 }

我们发现,但我们子进程修改全局变量g_val的时候,父进程的g_val没有受到影响,但是他们的地址都是一样的,这是为什么呢?

由此我们知道,这里的地址绝对不是物理内存的地址,而是虚拟地址(线性地址);并且几乎所有语言,如果有地址的概念,这个地址一定不是物理地址,而是虚拟地址。物理地址是由操作系统保管的。以下我们就开始介绍虚拟内存的作用

什么是地址空间

首先基本了解一下地址空间的排布情况
目前我们先不考虑解析这里的共享区

代码实现验证地址空间的排布

cpp 复制代码
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 int g_val = 100;
  5 int g_unval;
  6 int main(int argc,char *argv[],char *env[])
  7 {
  8   //代码区
  9   printf("code addr:%p\n",main);
 10   //初始化数据
 11   printf("init global addr:%p\n",&g_val);
 12   //未初始化数据
 13   printf("uninit global addr:%p\n",&g_unval);
 14   //堆区
 15   char* heap_mem = (char*)malloc(10);
 16   char* heap_mem1 = (char*)malloc(10);
 17   char* heap_mem2 = (char*)malloc(10);
 18   char* heap_mem3 = (char*)malloc(10);
 19   printf("heap_mem addr:%p\n",heap_mem);
 20   printf("heap_mem1 addr:%p\n",heap_mem1);
 21   printf("heap_mem2 addr:%p\n",heap_mem2);
 22   printf("heap_mem3 addr:%p\n",heap_mem3);
 23 
 24   //栈区
 25   printf("stack addr:%p\n",&heap_mem);
 26   printf("stack addr:%p\n",&heap_mem1);
 27   printf("stack addr:%p\n",&heap_mem2);
 28   printf("stack addr:%p\n",&heap_mem3);
 29 //字面常量
 30   const char *str = "helloworld";
 31   printf("read only string addr: %p\n", str);
 32   
 33   int i,j;
 34   //命令区                                                                                                
 35    for(i = 0 ;i < argc; i++)                                                                                                                                             
 36     {              
 37         printf("argv[%d]: %p\n", i, argv[i]);
 38     }        
 39   
 40  //环境区
 41  for(j = 0;env[j];++j)
 42  {
 43    printf("env[%d] addr:%p\n",j,&env[j]);
 44  }
 45 
 46   
 47   
 48   return 0;
 49 }

由此可见我们发现我们输入命令后,命令的地址在我们所执行的代码之后,这说明刚创建好这些变量就有了它自己本身的地址,地址程序结束后才打印,要分清前后
接下来我们来认识什么是地址空间

这时我们可以利用虚拟地址加映射机制(页表)来正确的讲地址存入物理内存

虚拟地址:不管哪个编译器,只要看到的地址都是虚拟地址,物理地址是操作系统保管的。

每一行代码都进行了编址。故,程序在编译的时候,每一个字段早已经具有了一个虚拟地址

=什么是映射机制?

映射机制可以将虚拟地址转换到物理地址,如果发现虚拟地址会越界或者错误,则就不会抛出,他起到了关键作用

那么映射机制是怎么判断的呢?

以上就是所描述的社么是地址空间,简单来说它是存储虚拟地址的。

地址空间和页表(用户级)是每一个进程都单独有一份的。
只要每一个进程的页表映射的是物理内存的不同区域,就可以做到进程之间不会互相干扰保证进程的独立性。

为什么要有地址空间

  1. 凡是非法的访问或者映射,os都会识别到,并终止你这个进程,有效的保护了物理内存。
    因为地址空间和页表是os创建并维护的,所以凡是使用地址空间和页表的都会在os的监控下来进行范文,这样就间接的保护了物理内存中的所有合法数据和各个进程,以及内核的相关有效数据
  2. 物理内存和进程的管理可以做到解耦合(没关联)。
    当我们申请了物理空间,但是我们不立即使用的时候,就会造成内存空间的浪费;
    针对这一现象,os做出了延迟分配的策略,来提高整机的效率。
    因为地址空间的存在,所有申请的空间都是在地址空间上申请的,物理内存不是被申请到一个字节,当我们真正访问物理地址的时候,才执行内存相关的算法。帮助申请内存,构建页表之间的映射关系,这些都是由os自主完成的
  3. 因为在物理内存中理论上随意加载,也是随意存放的,但是通过地址空间的虚拟地址和页表之间的映射,从进程视角来看所有的内存分布就成有序的了。
    因为有地址空间的存在,每一个进程都认为自己单独有一块4GB(32)空间,并且各个区域是有序的。进而通过页表映射到不同区域,来实现进程的独立性,各个进程是不知道其他进程的存在的

回答问题,为什么地址相同值不同

发生了写时拷贝!,所以父子进程各自其实在物理内存中,有属于自己的变量空间!只不过在用户层用同一个变量(虚拟地址!)来标识了

相关推荐
tan180°35 分钟前
Boost搜索引擎 网络库与前端(4)
linux·网络·c++·搜索引擎
Mr. Cao code1 小时前
Docker:颠覆传统虚拟化的轻量级革命
linux·运维·ubuntu·docker·容器
抓饼先生2 小时前
Linux control group笔记
linux·笔记·bash
挺6的还2 小时前
25.线程概念和控制(二)
linux
您的通讯录好友2 小时前
conda环境导出
linux·windows·conda
代码AC不AC3 小时前
【Linux】vim工具篇
linux·vim·工具详解
码农hbk4 小时前
Linux signal 图文详解(三)信号处理
linux·信号处理
bug攻城狮4 小时前
Skopeo 工具介绍与 CentOS 7 安装指南
linux·运维·centos
宇宙第一小趴菜4 小时前
08 修改自己的Centos的软件源
linux·运维·centos
bug攻城狮4 小时前
彻底禁用 CentOS 7.9 中 vi/vim 的滴滴声
linux·运维·服务器·centos·vim