Linux进程地址空间

🎬慕斯主页:修仙—别有洞天
♈️今日夜电波:HEART BEAT—YOASOBI
2:20━━━━━━️💟──────── 5:35
🔄 ◀️ ⏸ ▶️ ☰
💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍
目录
引入—从语言层面过渡到系统层面
什么是地址空间?
区域划分
为什么要有地址空间?
对地址空间学习的拓展
引入—从语言层面过渡到系统层面
在学习C/C++时,我们知道地址空间的大概布局图如下:

通过以下代码我们可以根据对应变量的地址空间来感受对应区域:
#include<stdio.h>
#include<stdlib.h>int un_gval;
int init_gval=100;struct s
{int a;int b;int c;
};int main(int argc, char* argv[], char* env[])
{printf("code addr: %p\n", main);char* str = "hello linux";printf("read only char addr: %p\n", str);printf("init global value addr: %p\n", &init_gval);printf("uninit global value addr: %p\n", &un_gval);char* heap1 = (char*)malloc(100);char* heap2 = (char*)malloc(100);char* heap3 = (char*)malloc(100);char* heap4 = (char*)malloc(100);static int a = 0;printf("heap1 addr : %p\n", heap1);printf("heap2 addr : %p\n", heap2);printf("heap3 addr : %p\n", heap3);printf("heap4 addr : %p\n", heap4);printf("stack addr : %p\n", &str);printf("stack addr : %p\n", &heap1);printf("stack addr : %p\n", &heap2);printf("stack addr : %p\n", &heap3);printf("stack addr : %p\n", &heap4);printf("a addr : %p\n", &a);int i = 0;for (; argv[i]; i++){printf("argv[%d]: %p\n", i, argv[i]);}for (i = 0; env[i]; i++){printf("env[%d]: %p\n", i, env[i]);}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;
}
child[23349]: 100 : 0x601058
parent[23348]: 0 : 0x601058
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:
变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
但地址值是一样的,说明,该地址绝对不是物理地址!在Linux地址下,这种地址叫做 虚拟地址我们在用C/C++语言所看到的地址,全部都是虚拟地址!
物理地址,用户一概看不到,由OS统一管理OS必须负责将 虚拟地址 转化成 物理地址 。
对此我们称之前在语言层面所看到地址空间为进程地址空间,不是实际的物理空间。实际的空间如下:为进程地址空间(也就是进程地址空间+页表(页表是一个映射表,它将虚拟地址转换为物理地址)+物理内存)。对于g_val值改变原因的理解,在g_val没有被子进程改变时,实际上父进程和子进程的虚拟地址映射的是同一块的物理地址。我们都知道父进程fork()后才会生成子进程,这个过程会让子进程拷贝一份父进程的PCB等等,对此对于页表也是会拷贝的,这个过程我们可以理解为C++中的浅拷贝。而在g_val被子进程改变后,这时子进程就不能与父进程指向同一块物理地址了,这个系统会给子进程开辟一块新的物理空间,而子进程的页表会更新这个新的物理地址。这个过程可以理解为C++中的深拷贝。如下:
什么是地址空间?
无论如何,地址空间也要被OS管理起来,每一个进程都要有地址空间,系统中,一定要对地址空间做管理!在了解地址空间前我们先了解一个概念—区域划分。
区域划分
在地址空间中的结构体定义了这样的一些变量用于区域划分:
unsigned long hiwater_rss; /* High-watermark of RSS usage */
unsigned long hiwater_vm; /* High-water virtual memory usage */unsigned long total_vm, locked_vm, shared_vm, exec_vm;
unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
由此可见,地址空间中的区域划分对于每一个区块是通过两个变量start、end来控制的,其中对应的地址可以被我们直接使用,而由于是用变量来管理的,对此我们很容易对空间进行区域的管理—比如堆栈相对而生。
对于什么是地址空间:地址空间在Linux内核中其实就是一个结构体。是一个内核数据结构。在Linux内核中是一个叫struct mm_struct的结构体,他最后会被struct task_struct也就是PCB用指针所指向:

为什么要有地址空间?
1、让进程以统一的视角看待内存,所以任意一个进程,可以通过地址空间+页表将乱序的内存数据变成有序,分门别类的规划好!
2、存在虚拟地址空间,可以有效的进行进程访问内存的安全检查!页表存在访问权限字段,可以根据字段防止非法读写。例如以下的代码:我们都知道字符常量区不能被修改,这是因为访问权限字段为只读。实际上,内存是可以随意读写的,有对应的限制是因为页表对应字段的控制,因此有相应的权限。
#include <stdio.h> #include <unistd.h> #include <stdlib.h>int main() {char *str = "hello Linux";*str = 'H'; return 0; }3、因为有页表的存在,地址空间可以将进程管理和内存管理解耦。通过页表,让进程映射到不同的物理内存处,从而实现进程的独立性!
对地址空间学习的拓展
1、每一个进程都有页表。
2、OS中有个CR3寄存器用于保存页表的地址(物理地址),用于进程的切换(联系PCB和数据的切换,页表也会跟着切换)。
3、页表中除了虚拟地址到物理地址的映射、访问权限字段外还有一个字段对应的物理地址是否分配和是否有内容。这就联系到了挂起的概念,如果系统中查页表发现该字段可以间接的判断该进程是否被挂起。
4、实际上在地址空间中的结构体中还定义了几个结构体指针变量进一步的控制地址空间的子区域划分,如果当前的地址空间也就是上面通过分别通过两个变量控制的地址空间不满足我们的需求了,而这时堆栈见还存在大量的空间,我们需要一小段的区域单独进行特定的映射,我们可以进行申请vm_area_struct的结构体对象:
struct vm_area_struct * mmap; /* list of VMAs */struct rb_root mm_rb;struct vm_area_struct * mmap_cache; /* last find_vma result */
而进一步挖掘他的结构体指针我们会发现这不就是上面所提到的根据两个变量进行一个区域的划分吗?注意下面还有个结构体指针,这说明在地址空间中,这个区域划分是一个链表,每一块划分都会根据链表连接,表头在地址空间中(由上面的代码可知):
struct mm_struct * vm_mm; /* The address space we belong to. */unsigned long vm_start; /* Our start address within vm_mm. */unsigned long vm_end; /* The first byte after our end addresswithin vm_mm. *//* linked list of VM areas per task, sorted by address */struct vm_area_struct *vm_next;
大致的结果如下,这才是完整的地址空间:

感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!

给个三连再走嘛~
相关文章:
Linux进程地址空间
🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:HEART BEAT—YOASOBI 2:20━━━━━━️💟──────── 5:35 🔄 ◀️ ⏸ ▶️ ☰ …...
2024.1.3 关于 Redis 渐进式遍历 和 数据库管理命令
目录 引言 渐进式遍历 SCAN 命令 数据库管理命令 切换数据库 获取数据库 key 个数 删除数据库所有 key 同步删除 SYNC 异步删除 ASYNC 阅读下述文章之前建议点击下方链接熟悉 keys 命令的用法和特点 Redis 全局通用命令 渐进式遍历 keys * 命令一次性将 Redi…...
并发编程:线程同步基础:5、读写锁。ReentrantReadWriteLock
1、主要方法 .readLock().lock();获取读锁 读锁之间互不干扰。 .writeLock().lock();获取写锁 写锁可以锁定住读锁和其他写操作。 2、主程序 package xyz.jangle.thread.test.n2_5.rwlock;import java.util.concurrent.TimeUnit;/*** * 读写锁。ReentrantReadWriteLock* a…...
SpringBoot 集成 Kafka消息中间件,Docker安装Kafka环境
前述 提供kafka、zooker在docker环境下进行安装的示例,springBoot集成kafka实现producer-生产者和consumer-消费者(监听消费:single模式和batch模式)的功能实现 环境安装 # 拉取镜像 docker pull wurstmeister/zookeeper docker pull wurstmeister/kafka# 运行zooker docker …...
阿里云Alibaba Cloud Linux 3镜像版本大全特性说明
Alibaba Cloud Linux阿里云打造的Linux服务器操作系统发行版,Alibaba Cloud Linux完全兼容完全兼容CentOS/RHEL生态和操作方式,目前已经推出Alibaba Cloud Linux 3,阿里云百科aliyunbaike.com分享Alibaba Cloud Linux 3版本特性说明ÿ…...
基于SSM的滁艺咖啡在线销售系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…...
【设计模式之美】理论一:怎么才算是单一原则、如何取舍单一原则
文章目录 一. 如何判断类的职责是否足够单一?二. 类的职责是否设计得越单一越好? 开始学习一些经典的设计原则,其中包括,SOLID、KISS、YAGNI、DRY、LOD 等。 本文主要学习单一职责原则的相关内容。 单一职责原则的定义:…...
MYSQL 深入探索系列六 SQL执行计划
概述 好久不见了,近期一直在忙项目的事,才有时间写博客,近期频繁出现sql问题,今天正好不忙咱们看看千万级别的表到底该如何优化sql。 案例 近期有个小伙伴生产环境收到了告警,有个6千万的日志表,查询耗时大…...
安装jupyter notebook,jupyter notebook的简单使用
借助anaconda安装jupyter notebook,先下载anaconda然后在Anaconda Prompt中输入命令: 输入"jupyter notebook",在默认浏览器中打开jupyter notebook。 输入"jupyter notebook --no-browser",启动服务器,但不打…...
宏集PC Runtime软件助推食品行业生产线数字化革新
一、前言 近年来,中国食品行业发展迅速且灵活多变,在当前经济下行的情形下,食品行业正面临着日益激烈的竞争,导致企业利润下降。 为了保持企业市场竞争力,国内某top10食品企业采用宏集SCADA解决方案—PC Runtime软件…...
python的课后练习总结3之条件语句
1,简单点,只有IF IF 后面加入条件然后冒号: 条件成立执行的代码1 条件成立执行的代码2 条件是否成立都执行的代码 身高 float(input(请输入你的身高(米):)) if 身高 > 1.3:print(f您的身高是{身高}米,请您买票) print(祝您旅途愉快) 2,IF 加个else if 条件:…...
RedisTemplate序列化
SpringBoot整合Redis,配置RedisTemplate序列化。如果使用StringRedisTemplate,那么不需要配置序列化,但是StringRedisTemplate只能存储简单的String类型数据,如图: 如果使用StringRedisTemplate存储一个常规对象&#…...
小米SU7汽车发布会; 齐碳科技C+轮融资;网易 1 月 3 日发布子曰教育大模型;百度文心一言用户数已突破 1 亿
投融资 • 3200 家 VC 投资的创业公司破产,那个投 PLG 的 VC 宣布暂停投资了• 云天励飞参与 AI 技术与解决方案提供商智慧互通 Pre-IPO 轮融资• 百度投资 AIGC 公司必优科技• MicroLED量测公司点莘技术获数千万级融资• 智慧互通获AI上市公司云天励飞Pre-IPO轮战…...
Python----matplotlib库
目录 plt库的字体: plt的操作绘图函数: plt.figure(figsizeNone, facecolorNone): plt.subplot(nrows, ncols, plot_number): plt.axes(rect): plt.subplots_adjust(): plt的读取和显示相关函数: plt库的基础图…...
PostgreSQL荣获DB-Engines 2023年度数据库
数据库流行度排名网站 DB-Engines 2024 年 1 月 2 日发布文章宣称,PostgreSQL 荣获 2023 年度数据库管理系统称号。 PostgreSQL 在过去一年中获得了比其他 417 个产品更多的流行度增长,因此获得了 2023 年度 DBMS。 DB-Engines 通过计算每种数据库 2024 …...
【每天五道题,轻松公务员】Day3:太阳常识
目录 专栏了解 ☞欢迎订阅☜ ★专栏亮点★ ◇专栏作者◇ 太阳常识 题目一 题目二 题目三 题目四 题目五 答案 补充扩展 专栏了解 ☞欢迎订阅☜ 欢迎订阅此专栏:考公务员,必订!https://blog.csdn.net/m0_73787047/category_1254…...
基于metersphere和supper-jacoco 测试覆盖率落地实践
一、背景及目标 背景 1、技术研发流程为测试 提供冒烟用例-开发根据用例自测-提测-开始测试,这一套流程,但是中间开发是否真实执行冒烟,测试并不知晓,而且测试提供冒烟用例是否符合标准也没法进行量化 2、公司产品属于saas产品&…...
LeetCode每周五题_2024/01/01~2024/01/05
文章目录 1599. 经营摩天轮的最大利润 [2024/01/01]题目题解 466. 统计重复个数 [2024/01/02]题目题解 2487. 从链表中移除节点 [2024/01/03]题目题解 1599. 经营摩天轮的最大利润 [2024/01/01] 题目 1599. 经营摩天轮的最大利润 你正在经营一座摩天轮,该摩天轮共…...
【华为OD机试真题2023CD卷 JAVAJS】抢7游戏
华为OD2023(C&D卷)机试题库全覆盖,刷题指南点这里 抢7游戏 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: A、B两个人玩抢7游戏,游戏规则为A先报一个起始数字X(10<起始数字<10000),B报下一个数字Y(X-Y<3),A再报一个数字Z(Y-Z<3),以此类推,直…...
14.7-时序反馈移位寄存器建模
时序反馈移位寄存器建模 1,阻塞赋值实现的LFSR,实际上并不具有LFSR功能1.1.1,RTL设计,阻塞赋值1.1.2,tb测试代码1.1.3,波形仿真输出,SIM输出,没实现LFSR1.2.1,RTL设计&am…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

