Linux程序地址空间

1. 进程地址空间

简单来说,就是从高地址往低地址,内存分区分别是:

  • 内核空间命令行参数argv环境变量env
  • 栈区:大部分局部变量,栈区内存往低处增长
  • 堆区:用于动态内存管理,堆区内存往高处增长
  • 数据段:存储全局变量静态数据
  • 代码段:存储可执行代码只读常量

我们有这样一个test1.c文件,可以把它运行起来查看它的内存地址是否这样安排。

结论:代码段 < 数据段 < 堆区 < 栈区 < 内核空间
1.同为数据段的内存,初始化过的init_value地址比未初始化的uninit_value地址更低,也就是数据段中初始化过的数据会存在更低的地址
2.同为堆区的内存,先开辟的heap1出现在最低的地址,后开辟的heap3出现在最高的地址,也就是堆区中越后开辟的内存,地址越高,地址是向高处增长的
3.同为栈区的内存,栈区中越后开辟的内存,地址越低,地址是向低处增长的

这样一套体系,叫做进程地址空间,事实上,着些地址并不是真实物理地址,而是虚拟地址。

2. 虚拟地址和物理地址

我们有这样一个test2.c文件,其内容为定义了一个value变量,父进程创建一个子进程,我们已经知道子进程和父进程共享代码数据,两个进程一同输出value的值和value的地址,子进程输出五次后将value改变为200,再来看看会发生什么情况。

以上输出结果中,父进程的value一直为100,这是毫无疑问的,因为进程具有独立性,父子进程的数据互不影响。子进程刚被创建时,和父进程共用数据和代码,因此父子进程第一次输出val的值的时候,不论值和地址都是一样的。

但是问题就出在子进程修改了value的值之后,我们发现,父子进程,输出地址是一致的,但是变量内容不一样!这已经不是语法问题了,而是计算机组成原理的问题,一块内存毫无疑问同时只能存储一个值。那为什么此处父子进程的value值不同,但是地址相同?那就只有一个可能:这个地址不是物理地址,而是假的地址!

能得出如下结论 :
变量内容不一样 , 所以父子进程输出的变量绝对不是同一个变量 , 但地址值是一样的,说明,该地址绝对不是物理地址! 在Linux 地址下,这种地址叫做 虚拟地址.
我们在用 C/C++ 语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由 OS 统一管理 , OS必须负责将 虚拟地址 转化成 物理地址

3. 页表

实际中,操作系统中有一个叫做页表的东西,其会维护虚拟地址与物理地址之间的映射关系,当进程通过虚拟地址在进程地址空间中查找数据,其实本质上是拿着虚拟地址到页表中查找映射关系,进而找到真实的物理地址,再对数据进行访问。

子进程被创建的时候,会继承父进程的大量数据,其中页表也会被继承,当子进程继承到父进程的页表时,大部分内容都不会改动,而是直接拷贝,包括虚拟地址物理地址的映射关系在内。

子进程继承到的页表,其虚拟地址和父进程是一样的,比如上图中,两进程ue的虚拟地址是一样的,因为子进程继承到了父进程中value的虚拟地址。当子进程对val进行修改的时候,此时发送写时拷贝:

子进程会把原先与父进程共用的value拷贝一份到别的地方,然后修改value = 200。这个过程中,对于子进程来说,value的物理地址改变了,于是对页表的映射关系进行修改,此时val的虚拟地址不变,但是虚拟地址对应的物理地址改变了!因此这个过程只修改物理地址,不修改虚拟地址。所以我们在修改了子进程中的val之后,观察到父子进程的value的地址一样,这是因为父子进程对value的虚拟地址是一样的,但是这个时候由于父子进程的页表不同,映射关系不同,最后访问到的物理地址其实是不一样的。因此我们输出的时候看到了一个地址两个值的情况。

1.页表相当于虚拟地址和物理地址的映射表,前面说过只有在进程运行时才会进行内存的访问。每个运行的进程的页表地址都会存在CPU里的一个名为cr3寄存器里。而当该进程被切换时,该进程会将该页表地址带走存在task_struct里,而当再次运行时又将页表地址放在cr3寄存器里。

2.页表内有对应的权限标志位用来表证它所对应的物理内存是可读还是可写。这也是为什么代码区和字符常量区是只读的,因为页表已经进行了权限管理。

3.页表内也有一个标志位用来判断数据释放在内存里。

4. 程序地址空间

在系统层面,也就是Linux系统中,进程地址空间被存储在PCB中,作为进程的一项属性。而进程地址空间本身被一个叫做mm_struct结构体管理。

整体统揽

意义

1.页表让进程以统一的视角看待内存—即虚拟内存映射物理内存,可以让物理内存任意分布,对应的进程都能找到对应的内存位置。

页表将无序的地址变为了有序的地址,当通过页表映射,把指向相同功能的内存地址放到一起,此时我们就有的栈区堆区静态区等等区域,更好地统一管理地址了。

2.进程地址空间可以有效的保护物理内存

当用于向内存发出非法访问时,进程地址空间就可以检测出来,比如访问越界的内存等等。此时内存中的数据不会受到任何影响,因为该错误已经被进程地址空间检测并处理了。比如我们通过指针向非法的内存进行写入,那么进程地址空间就可以检测出来该地址是超出了某个范围的,在操作系统层面就直接报错,而不会真的等到对内存写入了数据之后,才发现该访问非法。

3.因为有进程地址空间和页表的存在,实现了进程管理模块和内存管理模块实现了解耦合

由于页表的存在,此时进程管理和内存管理就是互不影响的。进程只需要去读取内存,申请内存等,无需考虑硬件层面的内存是如何管理的。对于磁盘,只需要做好加载数据到内存的工作,加载完数据后,无需考虑进程是如何读取地址,如何获取数据的。

4. 确保了进程的独立性

进程 = 内核数据结构 + 进程自己的代码和数据。通过进程地址空间的映射,每个进程都有自己的内核数据结构,自己的代码,自己的数据,相互之间完全独立互不影响。

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

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

相关文章

C # @逐字字符串

逐字字符串 代码 namespace TestAppConsole {class program{static void Main(string[] args){int a 0;int b 9;string c "2ui923i9023";//Console.Write(sizeof(int));string d "\t8282jjksk";string e "\t8282jjksk";Console.WriteLine(…

Java——继承(Inheritance)

一、继承简要介绍 1、继承是什么 在Java中&#xff0c;继承是一种面向对象编程的重要特性&#xff0c;它允许一个类&#xff08;子类或派生类&#xff09;继承另一个类&#xff08;父类或基类&#xff09;的属性和方法。继承的目的是实现代码的重用和设计的层次化。 子类通常…

LT8711GX 国产芯片 Type-C/DP1.4转HDMI2.1 用于加密狗 对接站

描述 LT8711GX是一款高性能的Type-C/DP1.4到HDMI2.1转换器&#xff0c;设计用于将USBType-C源或DP1.4源连接到HDMI2.1收发器。 该LT8711GX集成了一个符合DP1.4标准的接收器和一个符合HDMI2.1标准的发射器。此外&#xff0c;还包括一个CC控制器&#xff0c;用于CC通信&#xff0…

知名的以图叙事开源平台和工具

以图叙事是一种通过图表和图形来讲述故事或传达信息的方式&#xff0c;使复杂的数据更易于理解和更有吸引力。以下是一些知名的开源平台和工具&#xff0c;可以帮助你创建以图叙事的精彩内容&#xff1a; 1. StoryMapJS 描述: 一个简单的工具&#xff0c;用于创建由位置驱动的…

使用kali Linux启动盘轻松破解Windows电脑密码

破解分析文章仅限用于学习和研究目的&#xff1b;不得将上述内容用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。谢谢&#xff01;&#xff01; 效果展示&#xff1a; 使用kali Linux可以轻松破解Windows用户及密码 准备阶段&#xff1a; &#xff08…

洪水灾害的数据分析与预测

洪水是暴雨、急剧融冰化雪、风暴潮等自然因素引起的江河湖泊水量迅速增加&#xff0c;或者水位迅猛上涨的一种自然现象&#xff0c;是自然灾害。洪水又称大水&#xff0c;是河流、海洋、湖泊等水体上涨超过一定水位&#xff0c;威胁有关地区的安全&#xff0c;甚至造成灾害的水…

探索C++新特性:深入理解Lambda表达式

C不断演进&#xff0c;引入了新的特性和改进&#xff0c;使得语言更强大、更具表达力。其中&#xff0c;C11引入的Lambda表达式是最具影响力的特性之一。这个特性将匿名函数的能力带入C&#xff0c;允许开发者编写更简洁和清晰的代码。在这篇博客中&#xff0c;我们将探索C中的…

ASP.NET Core 使用Log4net

1. Nuget安装log4net&#xff0c;图里的两个 2.项目根目录下添加log4net.config.添加下面的代码: <?xml version"1.0" encoding"utf-8"?> <configuration><!-- This section contains the log4net configuration settings --><log…

C语言之常用内存函数以及模拟实现

目录 前言 一、memcpy的使用和模拟实现 二、memmove的使用和模拟实现 三、memset的使用和模拟实现 四、memcmp的使用和模拟实现 总结 前言 本文主要讲述C语言中常用的内存函数&#xff1a;memcpy、memmove、memset、memcmp。内容不多&#xff0c;除了了解如何使用&#x…

细说MCU的ADC模块单通道连续采样的实现方法

目录 一、工程依赖的硬件及背景 二、设计目的 三、建立工程 1、配置GPIO 2、选择时钟源和Debug 3、配置ADC 4、配置系统时钟和ADC时钟 5、配置TIM3 6、配置串口 四、代码修改 1、重定义TIM3中断回调函数 2、启动ADC及重写其回调函数 3、定义用于存储转换结果的数…

WHAT - SWR(stale-while-revalidate)HTTP 缓存失效策略 - 请求方案

目录 介绍传统数据请求的 React 代码示例SWR 的 React 代码示例SWR 的优势和不同之处 可复用组件真实示例特性解读自动重新请求1. 聚焦时重新请求2. 定期重新请求3. 重新连接时重新请求 条件数据请求1. 按需请求2. 依赖请求 数据更改1. 乐观更新2. 在数据更改后更新缓存3. 基于…

一个pdf分割成多个pdf,一个pdf分成多个pdf

在数字化办公和学习中&#xff0c;pdf格式因其良好的兼容性和稳定性而受到广泛欢迎。但有时候&#xff0c;我们可能需要将一个大的pdf文件分割成多个小文件&#xff0c;以便于分享、打印或编辑。今天&#xff0c;我就来教大家几种简单有效的方法&#xff0c;让你轻松实现pdf文件…

基于Wireshark和TiWsPC(Wireshark Packet Converter)的Zigbee抓包

前言 介绍几种Zigbee抓包方式&#xff1a; 1. Ubiqua 使用教程网上非常多也非常清晰&#xff1b; 但是Ubiqua是收费软件&#xff0c;较贵&#xff1b; 我安装过了&#xff0c;费好多事&#xff0c;没安装成功。 2. Killerbee套件 https://github.com/riverloopsec/killerbe…

WACV2023论文速览域迁移Domain相关

Paper1 CellTranspose: Few-Shot Domain Adaptation for Cellular Instance Segmentation 摘要原文: Automated cellular instance segmentation is a process utilized for accelerating biological research for the past two decades, and recent advancements have produc…

Ad-hoc命令和模块简介

华子目录 Ad-hoc命令和模块简介1.概念2.格式3.Ansible命令常用参数4.模块类型4.1 三种模块类型4.2Ansible核心模块和附加模块 示例1示例2 Ad-hoc命令和模块简介 1.概念 Ansible提供两种方式去完成任务&#xff0c;一是ad-hoc命令&#xff0c;一是写Ansible playbook(剧本)Ad-…

【电商纯干货分享】干货速看!电商数据集数据API接口数据分析大全!

数据分析——深入探索中小企业数字化转型&#xff0c;专注提供各行业数据分析干货、分析技巧、工具推荐以及各类超实用分析模板&#xff0c;为钻研于数据分析的朋友们加油充电。 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09…

02浅谈大模型文本生成的背后逻辑

02浅谈大语言模型文本生成的背后逻辑 两个概念&#xff1a; 通俗理解大模型文本生成逻辑 假设有一个prompt&#xff1a;How are you &#xff1f;&#xff0c;输入给大模型&#xff0c;那么大模型使怎么输出&#xff1f;

uni-app x 跨平台开发框架

目录 uni-app x 是什么 和Flutter对比 uts语言 uvue渲染引擎 组合式API的写法 选项式API写法 页面生命周期 API pages.json全局配置文件 总结 uni-app x 是什么 uni-app x&#xff0c;是下一代 uni-app&#xff0c;是一个跨平台应用开发引擎。 uni-app x 是一个庞…

使用 HAProxy 进行 MySQL 负载均衡

本章教程主要记录如何用HAProxy 实现MySQL负载均衡配置。 一、安装haproxy 在 Ubuntu/Debian 上&#xff1a; sudo apt-get update sudo apt-get install haproxy在 CentOS/RHEL 上&#xff1a; sudo yum install haproxy二、配置haproxy 编辑 HAProxy 配置文件&#xff08;…

ETAS工具导入Com Arxml修改步骤

文章目录 前言Confgen之前的更改Confgen之后的修改CANCanIfComComMEcuM修改CanNmCanSMDCMCanTp生成RTE过程报错修改DEXT-诊断文件修改Extract问题总结前言 通讯协议栈开发一般通过导入DBC实现,ETAS工具本身导入DBC也是生成arxml后执行cfggen,本文介绍直接导入客户提供的arxml…