摘要
本章主要是说一下地址空间,我也只是按照我的理解进行解释,可能说不清楚,欢迎指正
目录
摘要
一、空间布局图
二、代码测试一下
三、进程地址空间
四、测试代码
一、空间布局图
如下方图片可以看出地址空间有几种,这里没有画全,这里就是说一下正文代码空间也就是代码段、初始化数据、未初始化数据、堆、栈、命令行参数环境变量。
这里利用代码进行测试一下,看看是否和上面说的一样,如下方代码,这里测试李哥数据,如下方截图,在截图中可以看的出代码段的空间是最小的,如上方图中所示,代码空间是从下向上的,也就是下面最小上面最大,这里看可以从下方测试截图可以看出。
在下方测试截图中的可以看出栈的空间是向下增加的,堆的空间是向上增加的。
1 #include <stdio.h> 2 #include <stdlib.h>3 #include <unistd.h>4 5 int main()6 {7 printf("正文代码:%p\n",&main);8 int a=0;9 int b;10 printf("初始化数据空间:%p\n",&a);11 printf("未初始化数据空间:%p\n",&b);12 int* p1=(int*)malloc(10);13 int* p2=(int*)malloc(10);14 int* p3=(int*)malloc(10);15 int* p4=(int*)malloc(10);16 printf("申请的堆空间:%p\n",p1);17 printf("申请的堆空间:%p\n",p2);18 printf("申请的堆空间:%p\n",p3);19 printf("申请的堆空间:%p\n",p4);20 printf("申请的栈空间:%p\n",&p1);21 printf("申请的栈空间:%p\n",&p2);22 printf("申请的栈空间:%p\n",&p3);23 printf("申请的栈空间:%p\n",&p4);24 return 0;25 }
二、代码测试一下
如下图的测试就可以看出我定义了一个变量val去进行测试地址,结果在子进程中更改了数值,结果发现父进程的数值没有更改,但是两个地址是一样的,这是什么情况?得出了下方的结论:
变量内容不一样,所以父子进程输出的变量绝对不是同一个变量,但地址值是一样的,说明,该地址绝对不是物理地址!在Linux地址下,这种地址叫做 虚拟地址,我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理,OS必须负责将 虚拟地址 转化成 物理地址 。
4 int val=100;5 int main()6 {7 pid_t id=fork();8 printf("正文代码:%p\n",&main);9 int a=0;10 int b;11 printf("初始化数据空间:%p\n",&a);12 printf("未初始化数据空间:%p\n",&b);13 int* p1=(int*)malloc(10); 14 int* p2=(int*)malloc(10);15 int* p3=(int*)malloc(10);16 int* p4=(int*)malloc(10); 17 printf("申请的堆空间:%p\n",p1);18 printf("申请的堆空间:%p\n",p2);19 printf("申请的堆空间:%p\n",p3);20 printf("申请的堆空间:%p\n",p4);21 printf("申请的栈空间:%p\n",&p1);22 printf("申请的栈空间:%p\n",&p2);23 printf("申请的栈空间:%p\n",&p3);24 printf("申请的栈空间:%p\n",&p4);25 if(id==0)26 {27 int i=0;28 while(1)29 {30 if(i==5)31 {32 val=200;33 }34 printf("子进程:%d,地址:%p\n",val,&val);35 sleep(1); 36 i++; 37 } 38 }39 else 40 { 41 while(1) 42 { 43 printf("父进程:%d,地址:%p\n",val,&val); 44 sleep(1); 45 } 46 } 47 return 0;48}
三、进程地址空间
之前说‘程序的地址空间’是不准确的,准确的应该说成 进程地址空间 ,那该如何理解呢?看下方图片,这里就出现了一个名词叫做页表,这个页表也就是用来储存虚拟地址的,然后通过OS处理通过这个页表进行映射从而找到物理空间,这里就可以的出上面我所用代码得出的地址只是个虚拟地址,而更改了数据后,OS就把页表中储存的虚拟地址映射的物理地址换了一个地方,所以子进程和父进程的虚拟地址使用一个。
四、测试代码
#include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 int val=100;5 int main()6 {7 pid_t id=fork();8 printf("正文代码:%p\n",&main);9 int a=0;10 int b;11 printf("初始化数据空间:%p\n",&a);12 printf("未初始化数据空间:%p\n",&b);13 int* p1=(int*)malloc(10); 14 int* p2=(int*)malloc(10);15 int* p3=(int*)malloc(10);16 int* p4=(int*)malloc(10); 17 printf("申请的堆空间:%p\n",p1);18 printf("申请的堆空间:%p\n",p2);19 printf("申请的堆空间:%p\n",p3);20 printf("申请的堆空间:%p\n",p4);21 printf("申请的栈空间:%p\n",&p1);22 printf("申请的栈空间:%p\n",&p2);23 printf("申请的栈空间:%p\n",&p3);24 printf("申请的栈空间:%p\n",&p4);25 if(id==0)26 {27 int i=0;28 while(1)29 {30 if(i==5)31 {32 val=200;33 }34 printf("子进程:%d,地址:%p\n",val,&val);35 sleep(1); 36 i++; 37 } 38 }39 else 40 { 41 while(1) 42 { 43 printf("父进程:%d,地址:%p\n",val,&val); 44 sleep(1); 45 } 46 } 47 return 0;48}