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.选…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...