一.验证上图的正确性
代码:
#include <bits/stdc++.h>
using namespace std;
int g_unval;
int g_val = 100;
int main(int argc, char *argv[], char *env[])
{
//查看代码区:
printf("code addr: %p\n", main);
//查看初始化区
printf("init data addr: %p\n", &g_val);
//查看未初始化区:
printf("uninit data addr: %p\n", &g_unval);
char *heap = (char*)malloc(20);
char *heap1 = (char*)malloc(20);
char *heap2 = (char*)malloc(20);
char *heap3 = (char*)malloc(20);
//查看堆区:
printf("heap addr: %p\n", heap);
printf("heap1 addr: %p\n", heap1);
printf("heap2 addr: %p\n", heap2);
printf("heap3 addr: %p\n", heap3);
//查看栈区:
printf("stack addr: %p\n", &heap);
printf("stack addr: %p\n", &heap1);
printf("stack addr: %p\n", &heap2);
printf("stack addr: %p\n", &heap3);
//命令行参数
for(int i = 0; argv[i]; i++)
{
printf("argv[%d]=%p\n", i, argv[i]);
}
//环境变量:
for(int i = 0; env[i]; i++)
{
printf("env[%d]=%p\n", i, env[i]);
}
return 0;
}
我们发现确实是符合上速规则的。
二.一个问题引入虚拟空间地址
代码如下:
#include <bits/stdc++.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
using namespace std;
int g_val = 100;
int main()
{
pid_t id = fork();
if(id == 0)
{
int cnt = 0;
//子进程
while(1)
{
printf("child, pid: %d, ppid: %d, g_val: %d, &g_val: %p\n", getpid(), getppid(), g_val, &g_val);
sleep(1);
cnt++;
if(cnt == 5)
{
g_val = 200;
printf("child change g_val: 100->200\n");
}
}
}
else
{
while(1)
{
printf("father, pid: %d, ppid: %d, g_val: %d, &g_val: %p\n", getpid(), getppid(), g_val, &g_val);
sleep(1);
}
}
return 0;
}
我们发现将子进程中该变量:g_val的值变化之后,地址没变,即父进程和子进程指向的地址一样,但是访问的结果却不一样,这是什么原因呢???
所以这个地址绝对不是物理地址,我们应该叫虚拟地址/线性地址
所以我们会发现在我们C、C++中常说的地址都是虚拟地址,而非内存中的物理地址
我们知道进程具有独立性,所以每一个进程都有其所对应的虚拟地址,我们管其叫进程虚拟空间地址,所以上面子进场继承父进程在虚拟地址中位置,当其改变数据时,操作系统会将其在物理地址中位置改变,从而两者虚拟地址相同,但是物理地址不同,结果也就可以不一样了。
现在我们知道了虚拟空间地址,那么我们又是如何通过虚拟空间地址来找到物理地址的呢?
实际上存在一个页表的东西,可以将一个进程的虚拟空间地址和内存中的物理地址形成映射关系,而且在CPU中有一个寄存器叫:CR3,该寄存器存放了页表在内存中的地址可以满足CPU操作虚拟空间从而影响物理内存
补充:一个进程大概大概要有4G的虚拟空间
三.关于虚拟空间地址问题解答
为什么要有虚拟空间地址???直接读取内存不行吗?
实际上有了虚拟空间地址有以下几点好处:
1.将物理地址从无序变成有序,方便以统一视角去看待内存
2.将进程管理和内存管理进行解耦合(注意:低耦合可以更好)
3.我们可以用地址空间和页表来保护内存的重要手段
所以现在我们对进程进行新定义:
进程!=PCB+代码,而是==内核数据结构+代码
内核数据结构:指的是PCB+页码等
申请内存new/malloc/realloc会直接向内存中申请吗???
实际上是不会的,原因在于我们不一定会直接使用内存空间,如果开空间就直接申请,可能产生浪费,而操作系统要对效率和资源的利用率负责,所以实际上申请空间时只会在虚拟空间中申请,当我们需要写入内容数据时,才会通过页表来映射到内存上,通过一种叫“缺页中断”的方法实现
缺页中断:定义:当虚拟空间在页表中无对应的物理空间映射关系时,会先中断操作,再通过物理连接内存中空间,完成对应的映射,最后再次完成之前断开的操作!!!
以上就是关于虚拟空间的部分,感谢大家的支持!!!