引入
我们先来看一段代码
#include<stdio.h>
#include <unistd.h>
int g_val=200;//全局变量
int main()
{
int res=fork();
if(res>0)//father
{
printf("我是父进程。我的全局变量 g_val=%d,他的地址是 %p\n",g_val,&g_val);
}
else if(res==0)//子进程
{
g_val=100;
printf("我是子进程。我的全局变量 g_val=%d,他的地址是 %p\n",g_val,&g_val);
}
else{
printf("出错啦");
return -1;
}
return 0;
}
结果可能让人很,,,无措
同一个地址怎么会存储不同的值呢?
答案是:
这里的地址,绝对不是物理内存的地址!! ! ! ! ! ! ! ! ! ! ! !!
不是物理地址,而是:虚拟地址(线性地址)!
几乎所有的语言,如果他有“地址”的概念,这个地址一定不是物理地址,而是虚拟地址!! !
进程地址空间
什么是地址空间
1.验证地址空间的排布
-
代码演示
#include<stdlib.h>
#include<stdio.h>
int g_val=10;
int g_uval;
int main(int argc,char* argv[],char* envp[])
{
printf("代码区:%p\n",main);
char* str="abcde";
printf("只读常量区: %p\n",str);
printf("初始化数据区: %p\n",&g_val);
printf("未初始化数据区: %p\n",&g_uval);
int *p=(int*)malloc(10);
printf("堆区: %p\n",p);
printf("栈区: %p\n",&p);
printf("###############\n");
int i=0;
for(i=0;i<argc;i++)
{
printf("命令行参数:%p\n",argv[i]);
}
while(envp[i])
{
printf("环境变量: %p\n",&envp[i]);
i++;
}
return 0;
}
-
演示效果 对比排布
进程地址空间分为代码区,常量区,堆栈相对而生,命令行参数,环境变量
为什么要有地址空间
1.历史上过去是可以直接访问物理内存的,这种方式特别不安全。
现代计算机提出了下面的方式:
如何理解区域划分
上小学的时候,想来有很多同学都经历过38线吧。就像这样
struct desktop{
int start;
int end;
}
struct desktop one =[1,50]
struct desktop one =[51,100]
地址空间是一种内核数据结构,它里面至少有各个区域的划分
所谓的范围变化,本质是对start或者end标记值+ - 一定的范围即可
内核中的结构体名称是mm_struct ,地址空间和页表是每个进程都私有一份,只要保证,每一个页表映射的是物理内存的不同区域,就能做到,进程之间不会相互干扰,保证进程的独立性。
所以,开头的同一个地址存放不同的值也能理解了.
当我们的程序,在编译的时候,形成可执行程序的时候,没有被加载到内存中的时候,
请问:我们程序内部,有地址吗??
其实已经有地址了! ! !
可执行程序其实编译的时候,内部已经有地址了!
地址空间不要仅仅理解成为是OS内部要遵守的,其实编译器也要遵守!!!,即编译器编译代码的时候,就已经给我们形成了各个区域代码区,数据区,...并且,采用和Linux内核中一样的编址方式,给每一个变量,每一行代码都进行了编址,故,程序在编译的时候,每一个字段早已经具有了一个虚拟地址! ! !程序内部的地址,依旧用的是编译器编译好的虚拟地址
当程序加载到内存的时候,每行代码,每个变量边具有了一个物理地址,外部的
2.凡是非法的访问或者映射,0S都会识别到,并终止你这个进程!!!
有效的保护了物理内存吗! !
因为地址空间和页表是0S创建
并维护的!是不是也就意味着
凡是想使用地址空间和页表进行
映射,也--定要在OS的监管之下又
来进行访问! !
也便保护了物理内存
中的所有的合法数据
包括各个进程,以及内核的相关有效数据!
3.
1)因为在物理内存中理论上可以任意位置加载,那么是不是物理内存中的几乎所有的数据和代码在内存中是乱序的呢?
2)但是,因为页表的存在,它可以将地址空间上的虚拟
地址和物理地址进行映射,那么是不是在进程视角所有的内存分布,都可以是有序的! !
3)地址空间+页表的存在可以将内存分布,有序化!
4)地址空间是0S给进程画的大饼
5)结合第2条:进程要访问的物理内存中的数据和代码,可能目前并没有在物理内存中,同样的,也可以让不同的进程映射到不同的物理内存,是不是很容易做到
6)进程的独立性,可以通过地址空间+页表的实现!
结论:
因为有地址空间的存在,每-一个进程都认为自己拥有4GB空间(32),并且各个区域是有序的,进而可以通过页表映射到不同的区域,来实现进程的独立性! !