【Linux】进程地址空间

目录

一、程序地址空间

1、程序地址空间分布图:

2、通过代码验证上述分布图:

3、观察一个奇怪的现象(虚拟内存)

2023.12.03.2:00:00讲解具体原因(结合哈希表等等)

二、什么是进程地址空间?

1、进程与进程地址空间的关系

2、页表

3、为什么要有地址空间+页表

4、问题:


前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家

点击跳转到网站

一、程序地址空间

1、程序地址空间分布图:

2、通过代码验证上述分布图:

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 
  5 int g_uval;
  6 int g_val = 100;
  7 
  8 int main()
  9 {
 10     printf("代码段地址:%p\n",main);
 11     printf("初始化变量的地址:%p\n",&g_val);
 12     printf("未初始化变量的地址:%p\n",&g_uval);
 13     char* heap = (char*)malloc(20);
 14     printf("heap addr:%p\n",heap);
 15     printf("栈上的地址:%p\n",&heap);
 16 
 17     return 0;
 18 }
~         

可以看到地址的大小走向与程序地址空间分布图一致。
命令行参数表和环境变量表的地址比较:

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 
  5 int g_uval;
  6 int g_val = 100;
  7 
  8 int main(int argc,char* argv[],char*env[])
  9 {
 10     for(int i = 0;argv[i];i++)
 11     {
 12         printf("argv[%d]:%p\n",i,&argv[i]);
 13     }
 14     for(int i =0;env[i];i++)
 15     {
 16         printf("env[%d]:%p\n",i,env+i);
 17     }
 18 
 19     return 0;
 20 }

注意:先有命令行参数表,后有环境变量表(可搜索寻求原因)

可根据上面对比看出,不论是表还是表中的内容,地址都在栈上面;

3、观察一个奇怪的现象(虚拟内存)

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include <sys/types.h>
  5 
  6 int g_uval;
  7 int g_val = 100;
  8 
  9 int main(int argc,char* argv[],char*env[])
 10 {
 11     //观察一个奇怪的现象:
 12     pid_t id = fork();
 13     if(id == 0)
 14     {
 15         //子进程执行
 16         int cnt = 0;
 17         while(1)
 18         {
 19             printf("child process:\npid:%d\nppid%d\ng_val:%d\n&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
 20             sleep(2);
 21             cnt++;
 22             if(cnt == 5)
 23             {
 24                 g_val = 200;
 25                 printf("child change g_val:100->200\n");
 26             }
 27 
 28 
 29         }
 30     }
 31     else
 32     {
 33         //父进程执行
 34         while(1)
 35         {
 36             printf("father process:\npid:%d\nppid:%d\ng_val:%d\n&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
 37             sleep(2);
 38         }
 39     }
 40 
 41     return 0;
 42 }   

刚开始父子进程共享全局变量g_val,过了一会子进程将g_val由100修改为了200,发现子进程中g_val变为了200,但父进程中的g_val还是100,这不难理解,因为进程之间具有独立性,子进程修改变量不会影响父进程。

但奇怪的是,为什么父子进程中的g_val值不一样,但地址却是一样的。

原因在于,我们所看到的这些地址不是物理地址,而是虚拟地址(也叫线性地址)。说明我们平时写代码使用&取到的地址都不是物理地址,而是虚拟地址,同时也说明了进程地址空间也不是物理内存。

2023.12.03.2:00:00讲解具体原因(结合哈希表等等)

二、什么是进程地址空间?

每一个进程都会存在一个进程地址空间(假设范围为[0,4GB]);

操作系统也需要对进程地址空间进行管理,管理方法:先描述,再组织;

进程地址空间其实也是数据结构,具体到进程中,就是特定的数据结构对象;

1、进程与进程地址空间的关系

其实就是数据结果之间的关系:

我们知道进程PCB里面记录了关于进程的大部分信息,所以PCB里面也有一个进程地址空间结构体指针。进程地址空间也是一个结构体,里面有个自身类型指针,将各个进程地址空间以链接到某种数据结构中(比如链表),然后PCB中的进程地址空间结构体指针指向这个数据结构的起始地址,就这样管理起来了。

2、页表

区域划分本质就是说区域内的各个地址都可以使用。我们的地址空间不具备对我们的代码合数据的保存能力,是在物理内存中存放的。我们会通过进程地址的虚拟地址转化到物理内存中,这是通过页表实现的转化。

页表是一张哈希表,用于建立虚拟地址和物理地址的映射,从而通过虚拟地址找到对应的物理地址

3、为什么要有地址空间+页表

(1)可以将物理内存从无序变成有序,让进程以统一视角去看待内存。

(2)将进程管理和内存管理解耦合。

(3)也是内存安全的一个手段:比如遇到野指针这些问题,进程会直接挂掉,但不影响其他进程

4、问题:

(1)malloc和new申请内存时,申请的内存会直接立马使用?

当然是不一定的,什么时候用取决于用户,此时会在进程地址空间上面申请,当用户使用这份空间的时候才会通过页表去和物理内存建立映射。

(2)申请内存本质是在进程地址空间上申请的。

(3)好处:可以充分保证内存的使用率,不会空转;还会提升new和malloc的速度。

相关推荐
PWRJOY9 分钟前
Ubuntu磁盘空间分析:du命令及常用组合
linux·运维·ubuntu
田梓燊15 分钟前
专业课复习笔记 7
笔记·算法
ASDyushui20 分钟前
Shell 编程之正则表达式与文本处理器
linux·正则表达式
健康胡35 分钟前
仿射变换 与 透视变换
图像处理·人工智能·深度学习·opencv·算法·机器学习·计算机视觉
L_cl38 分钟前
【Python 算法零基础 2.模拟 ④ 基于矩阵】
python·算法·矩阵
2301_8076114941 分钟前
310. 最小高度树
c++·算法·leetcode·深度优先·回溯
zuozewei1 小时前
安全扫描之 Linux 杀毒软件 Clamav 安装
linux·运维·安全
@ chen1 小时前
常见排序算法及其java实现
java·算法·排序算法
wangchen_01 小时前
linux-信号保存和处理
linux·运维·服务器
Eric.Lee20211 小时前
conda 输出指定python环境的库 输出为 yaml文件
linux·python·conda