【Linux】进程地址空间

什么是进程地址空间?

我们来看一下这个例子:

复制代码
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>

int main()
{
    int val=1000;
    printf("I am father process,pid:%d, ppid:%d\n",getpid(),getppid());
    sleep(5);
    pid_t id =fork();
       if(id==0)
       {
          while(1)
          {
              val=200;
              printf("I am child process,pid:%d, ppid:%d, val:%d,   &val:%p\n",getpid(),getppid(),val,&val);
              sleep(1);
          }
      }
      else
      {
          while(1) 
          { 
              printf("I am father process,pid:%d, ppid:%d, val:%d,  &val:%p\n",getpid(),getppid(),val,&val);
              sleep(1);
          }
      }
}

运行结果:

根据之前的学习我们已经知道进程是有独立性的 ,所以在我们可以理解父子进程中val的值可以不一样,但是我们发现父子进程的val变量的地址是一样的,这是为什么?

从上面的运行结果来看,我们得到的val的地址不是真实的地址 (物理地址),因为同一时间内一个物理地址中只能存储一个进程的数据,不同进程的不同数据不可能同时存在于同一个物理内存中;

实际上OS会给每个进程创建一个独立的虚拟地址空间,通过页表将虚拟地址空间与物理地址一一对应;用户只能得到虚拟地址空间中的虚拟地址,当我们修改虚拟地址中的数据时,操作系统会先通过页表找到对应的物理内存,然后修改物理内存中的数据。

所以父子进程的val变量的地址 其实就是虚拟地址;因为子进程完全的父进程的拷贝;在子进程的val没有改变时,父子进程中val的虚拟地址都是0x7ffc83547fa8,通过页表找到的物理内存也都是一样的0x1122334455,如果子进程对val进行修改,那么OS就会在物理内存中寻找一块新空间,然后将原空间的数据拷贝到新空间,再修改子进程的页表映射关系,(也就是将原来的0x112233445修改为现在的物理地址)最后再修改新空间中 g_val 的值,上述过程叫做 写时拷贝。在这个过程中,我们并没有修改val对应的虚拟地址,所以我们查询到的地址是一样的;

根据上述的例子,我们就可以知道进程地址空间就是虚拟地址空间;

注:在OS中,进程地址空间中的地址通常也被称为线性地址,因为它是按比特位从全0到全1依次顺序编址的;磁盘程序内部的地址通常被称为逻辑地址;在Linux中,三者的意思是一样的,都表示虚拟地址,不用过于区分。

为什么要有地址空间?

上面我们知道的什么是地址空间,了解的地址空间是怎么管理的,那为什么要有地址空间呢?为什么不能直接把数据存放到物理内存中,反而要通过页表,地址空间一一映射到物理内存中?

是为了保护物理内存不受到任何进程内地址的直接访问,保证了数据的安全性;在虚拟地址到物理地址的转化过程中方便进行合法性校验;

如果进程直接访问物理内存,那么看到的地址就是物理地址,而语言中有指针,如果指针越界了,一个进程的指针指向了另一个进程的代码和数据,那么进程的独立性,便无法保证,因为物理内存暴露,其中就有可能有恶意程序直接通过物理地址,进行内存数据的篡改,如果里面的数据有账号密码就可以改密码,即使OS不让改,也可以读取。

  • 进程地址空间保证了数据的安全性

OS会给每个进程创建一个独立的虚拟地址空间,通过页表将虚拟地址空间与物理地址一一对应,当用户对某一进程的虚拟内存越界访问或者非法读取与写入时,页表或操作系统可以直接进行拦截,从而保证了内存中数据的安全

  • 进程地址空间保证了进程的独立性

对于互不相关的两个进程来说,它们都拥有自己独立的地址空间以及页表,页表会映射到不同的物理内存上,磁盘代码和数据加载到内存中的位置也不同,一个进程数据的改变不会影响另一个进程;

以上是进程地址空间的一部分,后续内容会慢慢补充!

相关推荐
叫致寒吧1 小时前
Tomcat详解
java·tomcat
ALex_zry1 小时前
Docker Compose运维技术实战分享:从安装到架构解析
运维·docker·架构
测试界的海飞丝4 小时前
10道软件测试面试题及其答案:
服务器·测试工具·职场和发展
t198751284 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk81634 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
S***26755 小时前
基于SpringBoot和Leaflet的行政区划地图掩膜效果实战
java·spring boot·后端
马剑威(威哥爱编程)5 小时前
鸿蒙6开发视频播放器的屏幕方向适配问题
java·音视频·harmonyos
@游子5 小时前
内网渗透笔记-Day5
运维·服务器
JIngJaneIL5 小时前
社区互助|社区交易|基于springboot+vue的社区互助交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·社区互助
晚风吹人醒.5 小时前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件