【Linux】程序地址空间

本文通过代码示例解释了进程地址空间的概念,强调了虚拟地址的重要性,指出在Linux中C/C++看到的地址是虚拟地址而非物理地址。文章还探讨了地址空间的作用,如统一内存访问视角和安全检查,以及进程管理和内存管理的解耦过程。
摘要由CSDN通过智能技术生成

程序地址空间回顾

  • 首先来看看概念图,有很多同学或多或少都听过图中的内容吧,但我们对他并不是很理解

使用代码来感受一下

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
 pid_t id = fork();
 if(id < 0){
 perror("fork");
 return 0;
 }
 else if(id == 0){ //child
  printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }else{ //parent
 printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }
 sleep(1);
 return 0;
}

  • 我们发现,输出出来的变量值和地址是一模一样的,很好理解呀,因为子进程按照父进程为模版,父子并没有对变量进行进行任何修改。可是将代码稍加改动

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
 pid_t id = fork();
 if(id < 0){
 perror("fork");
 return 0;
 }
 else if(id == 0){ //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
 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;
}

  • 我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:

  1. 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量

  2. 但地址值是一样的,说明,该地址绝对不是物理地址!

  3. 在Linux地址下,这种地址叫做虚拟地址

  4. 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理

  5. OS必须负责将 虚拟地址 转化成 物理地址

进程地址空间

  • 所以之前说‘程序的地址空间’是不准确的,准确的应该说成‘进程地址空间’,那该如何理解呢?看图:

  • 上面的图就足矣说名问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址!

为什么要有地址空间

  • 让进程以统一的视角看待内存。所以任意一个进程都可以通过地址空间+页表使得乱序的内存数据变得有序,分门别类规划好

  • 存在虚拟地址空间可以有哦晓得进行进程访问内存的安全检查

  • 页表的地址是物理地址,而不是虚拟地址

  • 把上下文(PCB、页表、mm_struct等)保存好,就等于将进程保存好了

  • 进程管理因为地址空间和页表的存在能够与内存管理解耦

进程和进程地址空间

  • 每一个进程运行后,都会有一个进程地址空间存在。都要在系统层面有自己的页表映射

  • 写时拷贝发生在物理内存中,由操作系统来做,不会影响上层语言

  • 空间范围:由一个极值到另一个极值,表示能访问地址的范围

  • 地址空间可以理解为操作系统给进程画的饼,它并不是真实的物理地址!

  • 地址空间也需要被操作系统管理起来,每一个进程都要有地址空间。系统中一定要对地址空间做管理

  • 区域划分:在计算机中用结构体来,且结构体中有_start和_end来区分

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 中,内核地址空间是操作系统内核独占的虚拟内存空间,用于存放内核代码、数据结构和驱动程序等。内核地址空间对用户进程是不可见的,用户进程无法直接访问和修改内核地址空间中的内容。 Linux 内核地址空间通常被划分为以下几个部分: 1. 物理内存映射区(Physical Memory Mapping):这个区域用于将物理内存映射到内核地址空间中,使得内核可以直接访问物理内存的内容。在这个区域中,每个物理页都有一个对应的内核虚拟地址,内核可以通过这些虚拟地址来访问物理内存。 2. 内核代码区(Kernel Code):这个区域存放了内核的代码,包括各种系统调用、中断处理程序和驱动程序等。内核代码区通常是只读的,以保证内核代码的完整性和安全性。 3. 内核数据区(Kernel Data):这个区域用于存放内核运行时的数据结构,如进程控制块(Process Control Block)、中断向量表、系统全局变量等。内核数据区中的数据可以被内核读写,但对用户进程来说是不可见的。 4. 内核堆(Kernel Heap):内核堆是内核动态分配内存的区域,用于存放内核运行时需要的临时数据结构和缓冲区等。内核堆的大小是可变的,根据需要进行扩展或收缩。 5. 内核栈(Kernel Stack):每个内核线程和中断处理程序都有自己的内核栈,用于保存函数调用的上下文信息。内核栈的大小通常比较小,以节省内存空间。 总体来说,Linux 的内核地址空间是操作系统内核独占的一块虚拟内存空间,用于存放内核代码、数据和驱动程序等。内核地址空间对用户进程是不可见的,用户进程无法直接访问和修改其中的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值