linux进程地址空间

一.验证上图的正确性

代码:

#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会直接向内存中申请吗???

实际上是不会的,原因在于我们不一定会直接使用内存空间,如果开空间就直接申请,可能产生浪费,而操作系统要对效率和资源的利用率负责,所以实际上申请空间时只会在虚拟空间中申请,当我们需要写入内容数据时,才会通过页表来映射到内存上,通过一种叫“缺页中断”的方法实现

缺页中断:定义:当虚拟空间在页表中无对应的物理空间映射关系时,会先中断操作,再通过物理连接内存中空间,完成对应的映射,最后再次完成之前断开的操作!!!

以上就是关于虚拟空间的部分,感谢大家的支持!!!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiaofi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值