前言
打怪升级:第52天 |
---|
一、进程地址空间
打怪升级之路开始!!
(一)进程地址空间是什么
在了解进程地址空间是什么之前我们先来见一见下方的程序运行结果:
示例:
#include<stdio.h>
#include<unistd.h> // sleep(); // getpid(); getppid();
#include<assert.h> // assert(); 断言
void Test02()
{
int num = 5;
pid_t ret = fork();
assert(ret != -1);
printf("创建了子进程\n");
if(ret == 0)
{
while(1)
{
// 子进程
printf("这是子进程,pid = %d, ppid = %d, num = %d, &num = %p\n", getpid(), getppid(), num, &num);
sleep(1);
num = 100; // 修改num
}
}
else
{
while(1)
{
// 父进程
printf("这是父进程,pid = %d, ppid = %d, num = %d, &num = %p\n", getpid(), getppid(), num, &num);
sleep(1);
}
}
}
int main()
{
Test02();
return 0;
}
运行实例:
“好,那我现在明白了:进程地址空间就是虚拟地址/线性地址 (地址从00到FF呈线性增长),但是,
我们为什么不直接使用内存地址,为什么要使用虚拟地址,为什么要通过页表转换来间接的找到内存地址呢,”
那么让我们继续往下探讨。。
(二)为什么要有进程地址空间
首先呢,让我们来想一想如果让进程直接使用内存地址会是什么样的:
由此我们得出地址空间的第一个作用 – 防止内存的随意访问,保护了物理地址和其他进程;
其次:
由此我们得出地址空间的第二个作用:进程管理和内存管理进行解耦合;
再次:
**
由此我们得出地址空间的第三个作用:可以让进程统一视角看待自己的代码和数据。
(三)重新理解进程地址空间
进程地址空间并不仅仅只影响OS的管理策略,还要让我们的编译器遵守这样的规则!
通过这样的对应转化就可以将虚拟地址和内存地址很好的对应起来。