Linux笔记---进程:进程地址空间
1. 地址空间
程序地址空间是指程序在执行期间可以访问的内存范围。它由操作系统为每个进程分配,以确保进程之间不会相互干扰。地址空间包含了程序所需的所有内存区域,包括代码、已初始化和未初始化的数据、堆(heap)、栈(stack)等。

2. 虚拟地址
什么是虚拟地址呢?我们在Linux笔记---进程:初识进程-CSDN博客中谈到过虚拟地址这一概念,现在再次回顾一下当时遇到的问题:
#include <stdio.h>
// fork函数包含在下面两个头文件中
#include <sys/types.h>
#include <unistd.h>int main()
{printf("我是一个进程,我的pid=%d,我即将创建子进程...\n", getpid());int id = fork();if(id == 0){printf("我是一个子进程,我的pid=%d,我父进程的pid=%d,我得到的id=%d,&id=%p\n", getpid(), getppid(), id, &id);}else{printf("我是一个父进程,我的pid=%d,我子进程的pid=%d,我得到的id=%d,&id=%p\n", getpid(), id, id, &id);}return 0;
}

由于fork函数返回值不同,对id写入的内容不同,导致id发生了写时拷贝,可以看到父子进程的id值确实是不同的。但问题是,二者的地址竟然是完全相同的?
当时我们说,这是因为这里的地址其实是虚拟地址,其物理地址可能指向不同的空间。
我们先思考一个问题,在同一次程序运行的过程中,同一个变量的地址会发生变化吗?当然不会。
既然子进程继承了父进程的数据,那么出现这样的结果似乎完全是在意料之中的,但问题是,这是如何做到的呢?
2.1 虚拟地址空间
实际上,每个进程都会有一个属于自己的虚拟地址空间,我们在程序中看到的、使用的,全部都是虚拟地址。虚拟地址空间中的地址会通过页表映射到物理地址空间。
这使得每个程序都认为自己能够使用整个内存空间。

程序地址空间通过虚拟内存和地址映射技术实现了进程的内存隔离,保障了多任务操作系统的安全和可靠性。例如,在一个简单的程序中,通过父进程创建子进程,并使用一个全局变量来证明虽然父子进程共用一套代码,但是数据是分离开的。这是因为每个进程都有自己独立的地址空间,通过页表映射到不同的物理内存上。
页表是操作系统内核用来管理虚拟地址和物理地址之间映射的一个数据结构。它的核心作用是支持虚拟内存,使得每个进程可以在自己的独立虚拟地址空间中运行,增强了内存隔离和安全性。
2.2 mm_struct
mm_struct是Linux内核中的一个数据结构,用于描述进程的内存管理信息,包括进程的虚拟地址空间布局、页表信息、内存区域等。它是内核中内存管理的核心数据结构之一,每个进程都有一个对应的mm_struct结构,用于管理该进程的内存空间。
struct task_struct
{/*...*///对于普通的⽤⼾进程来说该字段指向他的虚拟地址空间的⽤⼾空间部分,对内核线程来说这部分为NULL。struct mm_struct *mm; // 该字段是内核线程使用的。// 当该进程是内核线程时,它的mm字段为NULL,表⽰没有内存地址空间,可也并不是真正的没有,// 这是因为所有进程关于内核的映射都是⼀样的,内核线程可以使⽤任意进程的地址空间。struct mm_struct *active_mm; /*...*/
}struct mm_struct
{/*...*/struct vm_area_struct *mmap; /* 指向虚拟区间(VMA)链表 */struct rb_root mm_rb; /* red_black树 */unsigned long task_size; /*具有该结构体的进程的虚拟地址空间的⼤⼩*//*...*/// 代码段、数据段、堆栈段、参数段及环境段的起始和结束地址。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;/*...*/
}
- 虚拟区间:指进程的虚拟地址空间中的一个连续区域,这个区域具有特定的属性,如访问权限、是否映射到物理内存、是否与文件关联等。虚拟区间通常用于描述进程的代码段、数据段、堆区、栈区以及内存映射区域等。
- mmap:当虚拟区间较少时采用单链表进行管理,mmap指向这个链表。
- mm_rb:当虚拟区间较多时采用红黑树进行管理,mm_rb指向这棵树。
struct vm_area_struct {unsigned long vm_start; //虚存区起始unsigned long vm_end; //虚存区结束struct vm_area_struct* vm_next, * vm_prev; //前后指针struct rb_node vm_rb; //红⿊树中的位置unsigned long rb_subtree_gap;struct mm_struct* vm_mm; //所属的 mm_structpgprot_t vm_page_prot;unsigned long vm_flags; //标志位struct {struct rb_node rb;unsigned long rb_subtree_last;} shared;struct list_head anon_vma_chain;struct anon_vma* anon_vma;const struct vm_operations_struct* vm_ops; //vma对应的实际操作unsigned long vm_pgoff; //⽂件映射偏移量struct file* vm_file; //映射的⽂件void* vm_private_data; //私有数据atomic_long_t swap_readahead_info; #ifndef CONFIG_MMUstruct vm_region* vm_region; /* NOMMU mapping region */ #endif #ifdef CONFIG_NUMAstruct mempolicy* vm_policy; /* NUMA policy for the VMA */ #endifstruct vm_userfaultfd_ctx vm_userfaultfd_ctx; } __randomize_layout;
3. 虚拟地址空间的优势
- 地址空间扩展:使得程序在编写和运行时无需过于担心物理内存的实际容量限制。
- 内存保护:允许操作系统为不同的程序(进程)设置不同的内存访问权限。
- 内存共享:不同的进程可以通过虚拟内存机制共享某些内存区域。
- 进程管理与内存管理解耦:将实际的物理内存和程序使用的内存进行了分离,就像上文中有页表的那张图,以页表为分割,左边进行进程管理,右边进行内存管理,二者互不干扰并通过页表连接起来。
地址空间拓展与解耦的理解
假设某台计算机总的内存大小是128M,现在同时运行两个程序A和B,A需占用内存10M,B需占用内存110。计算机在给程序分配内存时会采取这样的方法:先将内存中的前10M分配给程序A,接着再从内存中剩余的118M中划分出110M分配给程序B。
若此时,占用20M的程序C也加入进来,计算机就无法为其分配空间,进程也就无法启动。
但如果程序采用虚拟地址空间,C进程在创建时就可以暂时先不加载代码和数据,仅仅将其task_struct和页表(此时仅有虚拟地址)维护起来(挂起状态)。
当C进程获得CPU资源时再将其他进程挂起,而将C进程的代码和数据加载到内存中,此时再将虚拟地址映射到实际的物理地址。
这样,尽管程序所需占用的内存空间大于计算机的内存空间,也能保证这些进程同时被启动,因为进程管理与物理内存的管理是被分割的。
4. 总结
Linux虚拟地址空间是操作系统为每个进程提供的一组虚拟地址,这些地址在进程看来是连续的,但实际上它们会被映射到物理内存的不同位置。虚拟地址空间的目的是使每个进程都认为自己独占了整个内存,从而简化内存管理和提高安全性。通过页表和MMU的配合,操作系统能够有效地管理和保护内存资源,同时提供了灵活的内存分配和共享机制。
因为有地址空间的存在,所以我们在C、C++语言上new, malloc空间的时候,其实是在地址空间上申请的,物理内存可以甚至一个字节都不给你。而当你真正进行对物理地址空间访问的时候,才执行内存的相关管理算法,帮你申请内存,构建页表映射关系(延迟分配),这是由操作系统自动完成,用户包括进程完全0感知!
相关文章:
Linux笔记---进程:进程地址空间
1. 地址空间 程序地址空间是指程序在执行期间可以访问的内存范围。它由操作系统为每个进程分配,以确保进程之间不会相互干扰。地址空间包含了程序所需的所有内存区域,包括代码、已初始化和未初始化的数据、堆(heap)、栈ÿ…...
flutter in_app_purchase google支付 PG-GEMF-01错误
问题:PG-GEMF-01错误 flutter 使用in_app_purchase插件升降级订阅时报错PG-GEMF-01。 解决方案: 升降级订阅时,确保不调用 MethodCallHandlerImpl.java文件中的 setObfuscatedAccountId()方法、setObfuscatedProfileId()方法 原因…...
“精神内耗”的神经影像学证据:担忧和反刍会引发相似的神经表征
摘要 重复性消极思维(RNT)包括面向未来的担忧和面向过去的反刍,两者在认知和情感上具有相似的特征。这些不同但相关的过程在大多程度上会激活重叠的神经结构尚不确定,因为大多数神经科学研究只单独研究担忧或反刍。为了解决这个问题,本研究使…...
Linux--Debian或Ubuntu上扩容、挂载磁盘并配置lvm
一、三块12TB组RAID 5 可用容量约24TB 二、安装LVM工具(已安装请忽略) sudo apt-get install lvm2二、查看可用磁盘 sudo lsblk 或者 sudo fdisk -l三、创建物理卷(PV) 选中刚做的磁盘组 sudo pvcreat /dev/sdb1四、创建卷组…...
【k8s】kubelet 的相关证书
在 Kubernetes 集群中,kubelet 使用的证书通常存放在节点上的特定目录。这些证书用于 kubelet 与 API 服务器之间的安全通信。具体的位置可能会根据你的 Kubernetes 安装方式和配置有所不同,下图是我自己环境【通过 kubeadm 安装的集群】中的kubelet的证…...
01-树莓派基本配置-基础配置配置
树莓派基本配置 文章目录 树莓派基本配置前言硬件准备树莓派刷机串口方式登录树莓派接入网络ssh方式登录树莓派更换国内源xrdp界面登录树莓派远程文件传输FileZilla 前言 树莓派是一款功能强大且价格实惠的小型计算机,非常适合作为学习编程、物联网项目、家庭自动化…...
【Windows 11专业版】使用问题集合
博文将不断学习补充 I、设置WIN R打开应用默认使用管理员启动 1、WIN R输入 secpol.msc 进入“本地安全策略”。 2、按照如下路径,找到条目: “安全设置”—“本地策略”—“安全选项”—“用户账户控制:以管理员批准模式运行所有管理员” …...
前端 vue3 + element-plus + ts 组件通讯,defineEmits,子传父示例
父组件: 子组件:...
【Django-xadmin】
时间长不用,会忘的系列 1、Django-xadmin后台字段显示处理 主要是修改每个模块下adminx.py文件 代码解释:第1行控制表单字段显示第2行控制列表字段显示第3行控制搜索条件第4行控制过滤条件第5行支持单个或多个字段信息修改第6行列表分页,每页显示多少行…...
Ubuntu24.04初始化教程(包含基础优化、ros2)
将会不断更新。但是所有都是基础且必要的操作。 为重装系统之后的环境配置提供便捷信息来源。记录一些错误的解决方案。 目录 构建系统建立系统备份**Timeshift: 系统快照和备份工具****安装 Timeshift****使用 Timeshift 创建快照****还原快照****自动创建快照** 最基本配置换…...
45 基于单片机的信号选择与温度变化
目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机,采用DS18B20检测温度,通过三种LED灯代表不同状态。 采用DAC0832显示信号脉冲,通过8位数码管显示温度。 信号脉冲可以根据两个按键分别调整为正弦…...
#JAVA-常用API-爬虫
1.爬虫 我们在正则表达式的讲解中可以使用字符串的方法materchs()来匹配,并且返回一个boolean值 String name "lshhhljh"; System.out.println(name.matches("lsh{3}\\s{3}")); //true现在我们将利用正则表达式来爬取本地或者网站上的文本内…...
Qt 面试题复习10~12_2024-12-2
Qt 面试题 28、Qt 如果一个信号的处理方法一直未被执行有哪些可能性29、Qt 三大核心机制30、虚函数表31、什么是Qt事件循环 ?32、纯虚函数和普通的虚函数有什么区别33、Qt 的样式表是什么?34、描述Qt的TCP通讯流程35、自定义控件流程36、什么是Qt的插件机…...
在OpenHarmony系统下开发支持Android应用的双框架系统
在 OpenHarmony 系统下开发支持 Android 应用的双框架系统,主要的目标是实现 OpenHarmony 本身作为底层操作系统,并通过兼容层或者桥接技术,允许 Android 应用在其上运行。双框架系统的架构设计会涉及到 OpenHarmony 和 Android 的结合&#…...
对力扣77组合优化的剪枝操作的理解
77. 组合 代码随想录放出了这一张图 我乍一看觉得想当然,但是仔细想想,又不知道以下剪枝代码作何解释,因此我想通过这篇文章简要解释一下 class Solution { private:vector<vector<int>> result;vector<int> path;void backtracking(int n, int k, int sta…...
SpringMVC中的Handler、HandlerMapping、HandlerAdapter
SpringMVC中的Handler、HandlerMapping、HandlerAdapter到底是啥 这东西,虽然说和我们的开发没啥关系,尤其是当你用SpringBoot进行开发时,这些接口离你越来越远了。讲实话,要不是这学期扫一眼学校的课件,我都不知道有这东西,这东西本来就是对使用框架进行开发的开发者隐藏…...
tomcat 8在idea启动控制台乱码
Tomcat 8在IntelliJ IDEA(简称IDEA)启动控制台出现乱码的问题,通常是由于Tomcat的默认编码格式(UTF-8)与IDEA或操作系统的默认编码格式(如GBK)不一致所导致的。以下是一些解决此问题的步骤&…...
windows下kafka初体验简易demo
这里提供了windows下的java1.8和kafka3.9.0版本汇总,可直接免费下载 【免费】java1.8kafka2.13版本汇总资源-CSDN文库 解压后可以得到一个文件夹 资料汇总内有一个kafka文件资料包.tgz,解压后可得到下述文件夹kafka_2.13-3.9.0,资料汇总内还…...
证明直纹极小曲面是平面或者正螺旋面.
目录 证明直纹极小曲面是平面或者正螺旋面 证明直纹极小曲面是平面或者正螺旋面 证明:设极小直纹面 S S S的参数表示为 r ( u , v ) a ( u ) v c ( u ) . (u,v)\mathbf{a}(u)v\mathbf{c}(u). (u,v)a(u)vc(u).则 r u a ′ v c ′ , r v c , r u ∧ r v a ′ ∧…...
matlab2024a安装
1.开始安装 2.点击安装 3.选择安装密钥 4.接受条款 5.安装密钥 21471-07182-41807-00726-32378-34241-61866-60308-44209-03650-51035-48216-24734-36781-57695-35731-64525-44540-57877-31100-06573-50736-60034-42697-39512-63953 6 7.选择许可证文件 8.找许可证文件 9.选…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
