[操作系统]——地址空间的作用和存在意义

一.什么是进程地址空间

        编程的时候我们经常和地址打交道,我们认为内存的布局是这样的,分成了许多不同的区域,不同区域用于存放不同数据,比如说局部变量存放在栈里,全局变量放在堆里,等等,同时我们认为地址是从下向上递增的.我们在调试的时候看到的地址也是这个地址,俗称进程地址空间。但其实系统真正的存储空间方式并不是这个而是物理地址空间。进程地址空间其实是一种数据结构,每一个进程都有自己的进程地址空间,也就是下图这张表。

        计算机的内存大小是固定的通常是4gb,8gb,16gb。而每个进程地址空间的大小都是内存的大小,这样一来对于每个进程而言,进程本身认为它可用的空间都是整个个内存大小,不同进程之间不知道其他进程的存在.

        

[操作系统]——地址空间的作用和存在意义_第1张图片

 二.为什么需要进程地址空间

假如没有进程地址空间,我们的数据都直接储存在物理地址空间,也就是真正的内存上,这种做法其实是非常危险的。因为内存是可以随时被读写的,这意味每个进程不再是独立的,不同进程之间有可能读取到对方的数据,这是很不安全的,例如因代码的问题造成野指针的问题就会导致意外发生。

三.进程地址空间的工作方法

首先我们要知晓一点,编译器在给代码编译地址的时候使用的也是虚拟地址,所以可以直接放在进程地址空间的相应区域,在创建完进程地址空间后还要创建页表,页表里储存的是虚拟地址和物理地址的映射关系。有点类似哈希表。进程最终是通过页表来访问物理内存的。同时因为一份进程对应一份进程地址空间,所以就算虚拟地址是相同的,只要页表对应到不同的物理内存,也能实现进程独立

四.案例

利用fork创建一个子进程,并修改值后,你会发现同一个地址打印出了两个值,这是因为虚拟地址相同,但映射后的物理地址不同。当子进程创建后,并完成它本身的进程地址空间和页表的建立,在修改前,子进程里的页表映射到确实是是最开始的物理地址,但当子进程试图修改该值是,他会先拷贝一份到另外的物理地址上再进行修改,这是两个进程val的虚拟地址是相同的,但物理地址已经不同了

int main()
{
int g_val = 0;
pid_t id = fork();

 if(id == 0)
    { 
        g_val=100;
        printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
else
    { //parent
        sleep(3);
        printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    sleep(1);
    return 0;
}

 五.总结

地址空间能有效的保护物理内存,同时可以延迟分配空间,提高效率,因为一开始创建进程地址空间的时候是没有给进程分配一丁点空间的。同时因为页表的存在,实现了进程管理模块和内存管理模块的解耦合,从而也实现了对进程任意位置的加载。因为页表本身的储存的物理地址是会随着进程的运行而更新的.同时页表不仅仅可以映射物理内存,也可以映射磁盘

你可能感兴趣的:(数据库,编辑器)