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

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

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

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

相关推荐
武子康几秒前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
苏-言7 分钟前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
小陈phd9 分钟前
Vscode LinuxC++环境配置
linux·c++·vscode
运维&陈同学12 分钟前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
是阿建吖!13 分钟前
【Linux】进程状态
linux·运维
界面开发小八哥14 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
二进制_博客18 分钟前
Flink学习连载文章4-flink中的各种转换操作
大数据·学习·flink
hzyyyyyyyu26 分钟前
内网安全隧道搭建-ngrok-frp-nps-sapp
服务器·网络·安全
草莓base27 分钟前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
codebolt40 分钟前
ADS学习记录
学习