【Linux】深入理解程序地址空间

🌟🌟作者主页:ephemerals__

🌟🌟所属专栏:Linux

目录

前言

一、什么是程序地址空间

二、深入理解程序地址空间

1. 引例

2. 理解地址转化

3. 再谈程序地址空间

4. 补充知识

总结


前言

        在现代操作系统中,进程的地址空间管理是实现多任务和内存保护的核心机制。对于Linux操作系统而言,理解程序的地址空间布局不仅对于开发高效、稳定的应用至关重要,也是调试和优化程序不可或缺的基础。本文将简要介绍Linux程序在内存中的地址空间结构,帮助读者更好地理解进程如何利用和管理内存资源。

一、什么是程序地址空间

        程序地址空间是指操作系统为一个程序分配的内存范围。在现代操作系统中,每个程序在运行时都有自己的程序地址空间

程序地址空间通常分为以下几个部分:

1. 内核空间:供操作系统使用,与其他部分形成隔离,程序无法访问。

2. 栈区:存储函数的局部变量和函数调用的上下文等。

3. 内存映射段(共享区):为支持文件的高效访问或多进程的数据共享而划分的一块区域,通常包含文件映射、动态库和匿名映射等。

4. 堆区:动态内存分配所用区域,需要手动管理。

5. BSS段:存储未初始化的全局变量和静态变量。

6. 数据段(静态区):存储已经初始化的全局变量和静态变量。

7. 代码段(常量区):存放程序的可执行代码和只读常量,该区域通常只读,不可修改

在32位系统下,程序地址空间一共有2^32个地址,大小为4GB;

在64位系统下,程序地址空间一共有2^64个地址,大小约为17179PB(是理论极限,实际比它小得多,并且整个内存大小远远达不到如此) 。

二、深入理解程序地址空间

1. 引例

         首先我们写一段程序:

#include <stdio.h>
#include <unistd.h>int main()
{int m = 0;pid_t id = fork();if(id == 0) // 子进程{m = 10;printf("子进程修改了m\n");sleep(1);printf("子进程:m = %d;&m = %p\n", m, &m);}else // 父进程{sleep(1);printf("父进程:m = %d;&m = %p\n", m, &m);}return 0;
}

这里我们使用fork创建了一个子进程,并让子进程修改m的值,此时会发生写时拷贝,两个进程的“m”应该不再表示同一份资源。接下来打印它们的值和地址。程序运行结果如下:

可以看到,出现了怪事:m的值不同,为什么它们的地址还相同呢?

只能说明:这个地址是假的,不是真实的内存地址(物理地址)。 

实际上,我们使用C/C++编程时使用到的地址,全部都是虚拟地址,并不表示真实的内存地址。为了保护物理内存,真实的内存地址是由操作系统统一管理的,用户无法直接访问。

2. 理解地址转化

        因此,刚才的例子当中,两个m的虚拟地址是相同的,但在物理层面,它们的物理地址是不同的。这就意味着两个进程的虚拟地址空间是不同的,并且操作系统必须将用户使用的虚拟地址转化为物理地址,然后进行访问等操作。负责虚拟地址和物理地址转化的东西,叫做页表

        我们可以暂时将页表理解为一个映射表,表的左边是虚拟地址,右边是物理地址,通过左边的虚拟地址就可以进行页表转化,找到真实的物理地址进行访问。

总结:

1. 一个进程具有一个程序地址空间

2. 一个进程具有一个页表,用于虚拟地址和物理地址的转化

3. 程序执行时,操作系统根据数据或代码的虚拟地址,通过页表找出对应的真实内存地址,进行访问。

3. 再谈程序地址空间

        因此,再说“程序地址空间”就不太准确了,我们称其为“进程地址空间”或“虚拟地址空间”更为恰当。

        实际上,不仅进程地址空间的地址是虚拟的,其“大小”也是虚拟的。进程地址空间就像是操作系统给进程画的一张大饼,让进程以为自己独占4GB的内存(32位系统下)。但由于其他进程可需要访问物理内存,物理内存总共就4GB,怎么可能被一个进程独占呢?所以虽说进程地址空间大小是4GB,但实际根本不可能有这么多。

        因此,进程在创建时,操作系统按照程序代码和数据的大小,创建地址空间,并设定各个区域的范围和内存大小,然后加载程序,申请相应的物理内存,再创建页表,支持将物理地址转化为虚拟地址,供上层用户使用。

        这样,我们就可以解释刚才的程序:

1. 子进程在创建之后,拷贝了父进程的进程地址空间以及页表,因此,父子进程的地址映射关系是相同的,具体表现就是虚拟地址相同,且维护的是同一块物理内存。

2. 此时子进程修改变量m的值,操作系统检测到变量要被修改,于时发生写时拷贝,在物理内存中对该变量进行拷贝,并修改子进程的页表映射关系,使原来的虚拟地址映射到别的物理地址处。这样,父子进程就各自维护一个m,它们表现出的虚拟地址相同,但物理地址不同,页表映射关系也不同,因此出现了地址相同,值不相同的情况。

那么为什么不支持直接访问物理内存,而这样大费周折地搞出一个什么进程地址空间和页表呢?有三点原因:

1. 如果每个进程都可以直接访问物理内存,那么就意味着这个程序可以直接修改另一个程序甚至操作系统的数据和代码,如果有恶意病毒程序,就会造成不可预料的后果。

2. 假设进程A需要申请地址为1~100的内存区域,并且代码中访问了地址为“50”的内存单元。下一次启动进程A时,如果已经有进程申请了1~100的内存区域,那么进程A如何申请内存呢?尚且申请101~200,但是代码中访问“50”已经写死了,没法修改,这导致每次程序执行的结果都是不确定的。

3. 如果直接使用物理内存,那么一个进程就是一整块内存区域,如果需要执行挂起或其他操作,就只能将整个区域都进行拷贝,效率降低。

进程地址空间的出现,就完美地解决了这些问题:

1. 地址转换过程中,可以对操作的合法性进行判定(页表中,针对虚拟地址空间中的各个区域,有明确的权限划分,假如在程序中修改常量数据,就会出现页表权限拦截,发生崩溃),从而保护物理内存,确保程序的正常执行。

2. 有了虚拟地址,物理内存申请就不必连续,经过页表可以转化成连续的虚拟地址,方便上层使用

3. 除此之外,程序地址空间还使得操作系统对进程的管理内存的管理之间进行一定的解耦合(用户申请内存根本无需关心物理内存的具体情况)

4. 补充知识

1. 虚拟地址空间的本质是一个数据结构,在Linux下叫做mm_struct,其地址存放在task_struct对象当中,mm_struct维护着一个个vm_area_struct,这些vm_area_struct存储着进程地址空间每一个区域的起始和结束地址。要调整区域划分,只需对其中变量进行加减操作。

2. 一个进程具有一个进程地址空间,意味着一个进程维护一个mm_struct,操作系统要将这些mm_struct组织起来统一管理。当进程数量较少时,mm_struct是用单链表结构组织起来的;较多时,利用红黑树结构进行组织。

总结

        本篇文章,我们学习了进程地址空间的基本概念,并深入理解了页表转化以及进程地址空间的本质。学习进程地址空间,为我们后续学习理解进程控制相关操作至关重要。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79399.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习-Day 5】Python 快速入门:深度学习的“瑞士军刀”实战指南

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

解决在 Linux 中 WPS 字体缺失问题

解决在 Linux 中 WPS 字体缺失问题 安装方式 安装方式 首先下载你所需要的字体文件 在字体文件所在的目录下右键点击在命令行中打开 或 Open in Terminal sudo mkdir /usr/share/fonts/myfontssudo cp ./* /usr/share/fonts/myfonts执行命令&#xff0c;更新字体缓存 sudo fc…

668SJBH报刊发行系统

1 前言 随着我国信息产业的迅猛发展&#xff0c;手工管理方式已不适应社务管理的要求&#xff0c;报社的日常管理正面临着信息化的挑战&#xff0c;采用计算机管理以提高服务质量和管理水平势在必行。发行管理是社务管理的一个重要组成部分&#xff0c;是报社和客户联系的纽带…

K8S - 从零构建 Docker 镜像与容器

一、基础概念 1.1 镜像&#xff08;Image&#xff09; “软件的标准化安装包” &#xff0c;包含代码、环境和配置的只读模板。 技术解析 镜像由多个层组成&#xff0c;每层对应一个Dockerfile指令&#xff1a; 应用代码 → 运行时环境 → 系统工具链 → 启动配置核心特性…

better_fbx 下载

目录 v6.0.5下载&#xff1a; better_fbx 下载 v6.0.5下载&#xff1a; Blender FBX模型导入导出插件 Better FBX Importer & Exporter V6.0.5V5.4.10 For Blender 2.8 | 龋齿一号GFXCamp better_fbx 下载 How To Install Launch Blender, navigate to Edit->User P…

Spring AOP 典型应用场景

AOP 典型应用场景 1. 日志记录&#xff08;Logging&#xff09;代码实现 2. 权限校验&#xff08;Authentication&#xff09;代码实现 3. 性能监控&#xff08;Performance Monitoring&#xff09;代码实现 4. 缓存处理&#xff08;Caching&#xff09;代码实现 5. 重试机制&a…

开始一个vue项目-day2

这次新增的功能有&#xff1a; 1、使用cookie存储token 参考网站:https://vueuse.org/ 安装包&#xff1a; npm i vueuse/integrations npm i universal-cookie^7 2、cookie的设置读取和删除&#xff0c;代码&#xff1a;composables/auth.js import { useCookies } from …

「Mac畅玩AIGC与多模态18」开发篇14 - 多字段输出与结构控制工作流示例

一、概述 本篇在输入变量基础上,演示如何通过执行 LLM 节点输出多个结构化字段,并传递至结束节点。开发人员将掌握如何配置结构化输出格式,实现提示词与字段的准确映射,为后续引入条件判断、循环结构等逻辑控制建立结构输出规范基础。 二、环境准备 macOS 系统Dify 平台已…

JWT解析

什么是JWT JSON Web Token &#xff08;JWT&#xff09; 是一种开放标准 &#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且独立的方式&#xff0c;用于在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任&#xff0c;因为它是经过数字签名的。…

C语言中的自定义类型 —— 结构体.位段.联合体和枚举

自定义类型 1. 前言2. 结构体2.1 结构体的声明2.2 结构体变量的定义和初始化2.3 结构体的特殊声明2.4 结构体的自引用2.5 结构体的内存对齐2.6 修改默认对齐数2.7 结构体传参 3. 位段4. 联合体5. 枚举6. 结言 1. 前言 在C语言中已经为用过户提供了内置类型&#xff0c;如&…

StarRocks 查询优化器深度解析

StarRocks 查询优化器概览 1. Development History of StarRocks 过去五年&#xff0c;StarRocks 发布了三个大版本&#xff1a; StarRocks 1.0&#xff1a;通过向量化引擎和 CBO&#xff0c;打造极速 OLAP 数据库。 StarRocks 2.0&#xff1a;通过主键模型、数据湖分析和查询…

如何提高情商?(优化版)

引言 提高情商&#xff08;EQ&#xff09;是一个需要长期练习和自我反思的过程&#xff0c;核心在于理解自己、管理情绪、共情他人并有效沟通。以下是一些具体且可操作的方法&#xff0c;结合理论和实际场景&#xff0c;帮助你逐步提升&#xff1a; 一、核心方法&#xff1a;…

Python爬虫实战:获取好大夫在线各专业全国医院排行榜数据并分析,为患者就医做参考

一、引言 在当今医疗资源丰富但分布不均的背景下,患者在选择合适的心血管内科医院时面临诸多困难。好大夫在线提供的医院排行榜数据包含了医院排名、线上服务得分、患者评价得分等重要信息,对患者选择医院具有重要的参考价值。本研究通过爬取该排行榜数据,并进行深入分析,…

【AI面试准备】电商购物车AI测试设计与实施

面试题&#xff1a;案例实践&#xff1a; 为电商购物车设计AI测试&#xff1a;通过用户行为日志训练点击路径预测模型&#xff0c;动态生成边界条件测试用例。 为了顺利通过面试&#xff0c;回答应结构清晰、技术深入&#xff0c;并突出实际应用与创新。以下为分步解答&#…

Java 中使用 Callable 创建线程的方法

一、Callable 接口概述​ Callable接口位于java.util.concurrent包中&#xff0c;与Runnable接口类似&#xff0c;同样用于定义线程执行的任务&#xff0c;但它具有以下独特特性&#xff1a;​ 支持返回值&#xff1a;Callable接口声明了一个call()方法&#xff0c;该方法会在…

2025-SMS短信验证服务或存风险,小心账号隐私“失守”

近期&#xff0c;火绒安全情报中心监测到一款伪装成具备SMS短信验证码接收服务的程序。该程序通过部署持久化后门&#xff08;即僵尸网络节点&#xff09;窃取敏感信息。火绒安全提醒广大用户务必从官方或可信渠道下载软件&#xff0c;避免因使用来路不明的程序而导致账号被盗或…

docker部署Open WebUI下载速度慢解决方法

docker pull ghcr.nju.edu.cn/open-webui/open-webui:main改成这个就可以了

气泡图、桑基图的绘制

1、气泡图 使用气泡图分析某一年中国同欧洲各国之间的贸易情况。 气泡图分析的三个维度&#xff1a; • 进口额&#xff1a;横轴 • 出口额&#xff1a;纵轴 • 进出口总额&#xff1a;气泡大小 数据来源&#xff1a;链接: 国家统计局数据 数据概览&#xff08;进出口总额&…

前端面经-VUE3篇(三)--vue Router(二)导航守卫、路由元信息、路由懒加载、动态路由

一、导航守卫 vue Router 中的 导航守卫&#xff08;Navigation Guards&#xff09; 是一个非常重要的功能&#xff0c;用于在路由切换过程中&#xff0c;拦截、控制、检查或延迟页面跳转。 你可以理解为&#xff1a; &#x1f510; “进门前的保安”&#xff0c;控制哪些页面…

MATLAB实现二氧化硅和硅光纤的单模光波特性与仿真

一.二氧化硅和硅光纤的单模光波特性 利用麦克斯方程的精确解研究二氧化硅和硅亚波长直径导线的单模光波特性。研究了单模条件、模场。 二氧化硅光纤导线是圆形截面&#xff0c;包层是空气包层&#xff0c;阶梯型变化的折射率&#xff0c;导线线径D非常小长度足够长&#xff0…