【Linux】程序地址空间

程序地址空间

  • 初识程序地址空间
  • 进程地址空间
  • 一些补充
    • 虚拟地址转物理地址的工作谁来做?
    • 进程地址空间存在的意义
    • 回看new/malloc
  • 进程中的写时拷贝
    • 一点延申

初识程序地址空间

在这里插入图片描述
运行结果如下:
在这里插入图片描述
  我们发现父进程和子进程打印出来的值和地址都是一样的,我们暂时理解为子进程是以父进程为模板创建的,且父进程和子进程都没有对变量进行修改
在这里插入图片描述
运行结果如下:
在这里插入图片描述
  通过运行结果可以发现:即使是在子进程中对变量做了修改,但是打印出来的变量地址却是不一样的,可是变量的内容却又不一样。此时的变量仿佛就是随时可变的。此刻我们不妨大胆假设,这看似是一个变量,但是实际上已经是两个变量了,即变量的内容不一样,所以才会导致父子进程输出的变量绝对不会是同一个变量
  既然已经不是同一个变量了,虽然打印出来的地址是一样的,这就意味着这个地址不会是真实的物理地址
  在Linux中,这种地址叫做虚拟地址或者是线性地址
  其实,我们平时所用的语言级别的地址都是虚拟地址而非物理地址,物理地址是用户看不到的,而是由操作系统来统一管理,所以有得出一条很重要的结论:操作系统必须负责将虚拟地址转化为物理地址

进程地址空间

  其实,程序地址空间这个说法是不太准确的,准确的应该称作为进程地址空间
在这里插入图片描述
什么是进程地址空间?
  每个进程都为了自身需要一定的内存空间,由于进程很多,随之而来的空间的需求也逐渐变大,操作系统为了更好的管理进程及其对应的空间,就有了进程地址空间这样一个概念,地址空间实质上是以一个数据结构,具体到某个进程,就是特定的数据结构对象。

//可以将地址空间理解为这样
struct mm_struct//进程地址空间
{int code_start;int code_end;int heap_start;int heap_end;//...(其余相关属性,用整数描述起来的各个区域)struct mm_struct*next;
}

  地址空间是一个内核数据结构,该数据结构中存的是各个区域的划分。但是要注意的是地址空间并不具备对代码数据的保存能力,数据和代码都是被存放到物理内存中的。
  也就意味着,当我们拿到地址空间上的地址后(虚拟地址),还需要将这个地址经过一定的转化变成真实地址才能拿到具体的数据。于是,操作系统就会为进程提供一张用于映射的表——页表

一些补充

虚拟地址转物理地址的工作谁来做?

  CPU中存在一个寄存器叫做CR3,保存的是当前进程页表的起始地址(存的是物理地址),当要对某个数据进行修改的时候,就会通过CR3来找到页表,进而通过页表将虚拟地址找到该数据的真实物理地址,就可以访问到物理内存上的数据。而查找和转化工作是由CPU中的一个硬件叫做mmu(memory management unit可翻译成内存管理单元)完成

进程地址空间存在的意义

  1. 将物理内存从无序变为有序,让进程以统一的视角看待内存
  2. 将进程管理和内存管理进行解耦合(即进程管理和内存管理各管各的,相互不影响)
  3. 内存访问权限控制:页表可以记录每个页(页面)的访问权限,包括读、写、执行等权限。当程序试图访问不属于自己的内存页或越界访问时,硬件和操作系统可以根据页表的权限设置进行拦截和处理,从而防止非法的内存访问,确保内存的安全性。
  4. 隔离不同进程:通过使用地址空间和页表,操作系统可以将不同进程的内存空间隔离开来,确保它们互相不会干扰对方的内存数据。每个进程都有自己的地址空间和页表,这样即使多个进程运行在同一台计算机上,它们也不会相互影响。

回看new/malloc

#include<stdio.h>
#include<stdlib.h>int main()
{int*p=(int*)malloc(sizeof(int));free(p);return 0;
}

当我们申请一段空间时,我们会直接使用吗?
  答案是不一定,就像上面的代码,我申请了一个整形的空间,但是却没有使用,此时操作系统在执行这段语句的时候,并不会立刻分配一个整形的空间,而是当我在真正写入数据的时候,操作系统才在物理内存中开辟空间并在页表中建立从虚拟地址到物理地址的映射关系(在操作系统进行这些操作的时候,会发生缺页中断),然后中断恢复,最后再进行写入操作。在缺页中断之前,也就是操作系统并没有在物理内存中申请空间之前,p中存的只是一个没有建立映射关系的虚拟地址

进程中的写时拷贝

  之前的有关进程的博客就提到过,子进程和父进程是共享数据的,当子进程或者是父进程要对中间的数据做一些写入的时候,就会发生写时拷贝,这里就针对于写时拷贝做一些更详细的介绍
为什么要存在写时拷贝,直接在内存中重新申请一块空间不可以吗
  如果说只是对原数据做一点修改的话(比如位操作),不拷贝怎么知道原来的数据是什么

怎么实现的写时拷贝?
  其实之前的页表并不是很完整,页表上不只是包括了从虚拟地址到物理地址的映射关系,还包括了对于读写权限的限制等,这里的话就只增加一个权限位
在这里插入图片描述
  数据段征程情况下是可以进行读写的,但是当父进程创建了子进程之后,数据段的权限就变成了只读(此时父子进程的页表中的权限位全部都是只读),后来当某个进程要修改数据段(假设该数据存在于栈区)的某个数据并尝试写入时,因为当前的映射条件是只读,要修改数据就会导致转化工作出问题,操作系统此时介入,并触发缺页中断。
  操作系统一看,这个数据段存在于栈区,确实是可以做写入,操作合理,但是此时页表上的写的权限为已读,操作系统就会进行写时拷贝,建立映射关系,并对相应的权限进行修改

一点延申

int main()
{const char*str="hello world";*str='H';return 0;
}

  对于以上代码的结果,我们不难看出当对于字符串进行修改的时候,时会出现报错的,因为字符串常量在常量区,不可以被修改
  但是现在,我们要对于所谓的“常量区”有更进一步的理解,什么叫做常量区?
  str保存的是这个常量字符串的起始地址,而这个地址是虚拟地址,当进行解引用并试图将字符H写入到字符串中时,注定要发生由虚拟地址到物理地址的转换,此时的权限为“只读”,页表根据权限判定写入操作不符合要求所以会失败
  正是因为存在页表,而页表中存在权限位,就有了语法中的“常量不可以被修改”的结论

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

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

相关文章

花生壳 | ubuntu安装和卸载花生壳

一、到花生壳官网下载linux版本的花生壳 一般下载到Downlaods文件夹 进入文件夹 dpkg -i phddns_5_1_amd64.deb #安装花生壳 dpkg -r phddns #卸载花生壳 登录花生壳管理网站 http://b.oray.com 在Ubuntu中输入命令查看sn码&#xff0c;默认密码为admin phddns status …

01.绝对路径和相对路径(Linux基本概念)

基础认知&#xff1a; 电脑的目录结构是一颗多叉树。不管是Linux还是windows&#xff0c;目录结构都是一样的。所以我们在查找某个目录或者文件的时候&#xff0c;本质就是在多叉树结点的查找。多叉树示例图如下&#xff1a; ​​​​​​​ ​​​​​​​ ​​…

Unity发布webgl设置占满浏览器运行

Unity发布webgl设置占满浏览器运行 Unity发布webgl的时候index.html的模板文件 模板文件路径&#xff0c;根据自己的需求修改。 C:\Program Files\Unity\Hub\Editor\2021.1.18f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default再桌面新建一个t…

飞桨AI应用@riscv OpenKylin

在riscv编译安装飞桨PaddlePaddle参见&#xff1a; 算能RISC-V通用云编译飞桨paddlepaddleopenKylin留档_在riscv下进行paddlelite源码编译-CSDN博客 安装好飞桨&#xff0c;就可以用飞桨进行推理了。刚开始计划用ONNX推理&#xff0c;但是在算能云没有装上&#xff0c;所以最…

【Linux】从零认识进程 — 中下篇

送给大家一句话&#xff1a; 人一切的痛苦&#xff0c;本质上都是对自己无能的愤怒。而自律&#xff0c;恰恰是解决人生痛苦的根本途径。—— 王小波 从零认识进程 1 进程优先级1.1 什么是优先级1.2 为什么要有优先级1.3 Linux优先级的特点 && 查看方式1.4 其他概念 2…

SpringBoot 邮件服务集成配置全面解析

前言 本文以网易邮箱&#xff08;及 163 邮箱&#xff09;为例&#xff0c;展示如何为 SpringBoot 项目集成邮件服务&#xff0c;其他邮箱配置类似&#xff0c;可以自行查看 Spring Email 指南 或是其他官方文档 授权码 首先我们需要获取授权码&#xff0c;用于后续配置&…

[Linux]知识整理(持续更新)

前言 Linux的目录结构 Linux的目录结构是一个树型结构 Windows 系统可以拥有多个盘符, 如 C盘、D盘、E盘 Linux没有盘符这个概念, 只有一个根目录 /, 所有文件都在它下面 Linux路径的描述方式 第一章 基本命令 命令格式 例&#xff1a;ls –la /etc 说明&#xff1a; 1…

Centos上安装Harbor并使用

harbor的安装与使用 Harbor介绍安装前的准备工作为Harbor自签发证书安装Harbor安装docker开启包转发功能和修改内核参数安装harbor扩展 Harbor 图像化界面使用说明测试使用harbor私有镜像仓库从harbor仓库下载镜像 Harbor介绍 容器应用的开发和运行离不开可靠的 镜像管理&…

Webman全局异常捕获处理

最近在使用webman这个框架做项目开发&#xff0c;涉及到需要统一处理异常捕获。由于官网给的并不详细&#xff0c;于是自己实现了一下全局异常处理类。 一、配置效果 例如&#xff1a;我要在项目中统一返回json 格式数据&#xff0c;并不想在业务层写try,catch逻辑。 或者在业务…

c++之类与对象<一>

目录 一&#xff1a;类的引入 二&#xff1a;类的两种定义方式 1.声明和定义都放在类中 2.类声明放在.h文件中&#xff0c;将成员函数定义放在.cpp文件中 三&#xff1a;类的访问限定符及封装 1.访问限定符 2.使用规则 3.c中struct和class的区别是什么 4.封装 四…

抖音平台热销的本腾和新讯随身WiFi,哪个更靠谱,更值得购买?

经常有粉丝朋友摆脱小编测评一下在某短视频平台上面非常火爆的两款随身WiFi&#xff0c;本腾随身WiFi和新讯随身WiFi到底哪个更好。今天&#xff0c;小编就为大家带来最真实的体验测评。 一、外观和产品 这方面新讯要比本腾做的更好&#xff0c;本腾的设备相对单一一些。新讯则…

鸿蒙Harmony应用开发—ArkTS(@Link装饰器:父子双向同步)

子组件中被Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。 说明&#xff1a; 从API version 9开始&#xff0c;该装饰器支持在ArkTS卡片中使用。 概述 Link装饰的变量与其父组件中的数据源共享相同的值。 限制条件 Link装饰器不能在Entry装饰的自定义组件中使用…