目录
1、一段代码引出一个问题
1 #include<stdio.h>
2 #include<unistd.h>
3 int g_val = 100;
4
5 int main()
6 {
7 pid_t id = fork();
8 if(id == 0)
9 {
10 // 子进程
11 int i = 0;
12 while(1)
13 {
14 printf("I am child process, id:%d, g_val:%d, &g_val:%p\n", getpid(), g_val, &g_val);
15 i++;
16 if(i == 5)
17 {
18 g_val = 200;
19 printf("Child process changed g_val success!!!\n");
20 }
21 sleep(1);
22 }
23 }
24 else {
25 while(1)
26 {
27 printf("I am parent process, id:%d, g_val:%d, &g_val:%p\n", getpid(), g_val, &g_val);
28 sleep(1);
29 }
30 }
31 return 0;
32 }
运行结果:
[yzl@VM-4-5-centos tmp]$ ./proc
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:100, &g_val:0x601054
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:100, &g_val:0x601054
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:100, &g_val:0x601054
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:100, &g_val:0x601054
Child process changed g_val success!!!
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:200, &g_val:0x601054
I am parent process, id:28298, g_val:100, &g_val:0x601054
I am child process, id:28299, g_val:200, &g_val:0x601054
讨论:
上述代码为,创建子进程,若干秒后,子进程改变全局变量值,发现子进程与父进程打印此全局变量值时,值不同,且地址相同。
同一个地址处的值在同一时刻不可能不同,于是引出了虚拟地址空间的概念。即这里子进程与父进程打印的地址并非实际的物理地址,而是一种虚拟地址(线性地址)。
2、Linux下进程虚拟地址空间分布
虚拟地址空间使得每个进程看待内存时都有一个统一的视角,并且在他们看来,内存的分布是井然有序的。具体分布如下图
1. 栈堆相向增长,堆向高地址增长,栈向低地址增长。这两个区域是动态变化的。
2. 虚拟地址空间分为两个空间:1. 内核空间,在32位下占1G 2. 用户空间,在32位下占3G
即[0, 3GB] 用户空间 [3GB, 4GB] 内核空间
3. static修饰局部变量,本质上是将此变量属性变为全局属性,存储在全局区。而语法的限制使得此static变量仅能在局部可见。
4. 上图虚拟内存分布仅适用于Linux操作系统,不适于Windows。
5. 一个有关堆区的知识:当C语言使用malloc函数时,申请10字节空间,实际在内存中会占用大于10字节的空间,多出的空间用于存储一些属性。这也是为什么free时传首地址即可,而不需要传空间大小。