【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的速度。

相关推荐
能工智人小辰13 分钟前
Codeforces Round 509 (Div. 2) C. Coffee Break
c语言·c++·算法
kingmax5421200814 分钟前
CCF GESP202503 Grade4-B4263 [GESP202503 四级] 荒地开垦
数据结构·算法
岁忧19 分钟前
LeetCode 高频 SQL 50 题(基础版)之 【高级字符串函数 / 正则表达式 / 子句】· 上
sql·算法·leetcode
梦星辰.22 分钟前
VSCode CUDA C++进行Linux远程开发
linux·c++·vscode
远方160930 分钟前
0x-2-Oracle Linux 9上安装JDK配置环境变量
java·linux·oracle
cui_win36 分钟前
每日一令:Linux 极简通关指南 - 汇总
linux·运维·服务器
知星小度S1 小时前
Linux权限探秘:驾驭权限模型,筑牢系统安全
linux·运维·服务器
eachin_z1 小时前
力扣刷题(第四十九天)
算法·leetcode·职场和发展
黄交大彭于晏1 小时前
发送文件脚本源码版本
java·linux·windows
闻缺陷则喜何志丹1 小时前
【强连通分量 缩点 拓扑排序】P3387 【模板】缩点|普及+
c++·算法·拓扑排序·洛谷·强连通分量·缩点