Linux:进程地址空间

目录

1.程序地址空间 

2.进程地址空间


1.程序地址空间 

我们在讲C/C++语言的时候,32位平台下,我们见过这样的空间布局图

我们来验证一下这张图的正确性:

  int un_gval;int init_gval=100;int main(int argc, char* argv[],char* env[]){//代码区printf("code addr: %p\n",main);//字符常量区const char *str = "hello Linux";//*str = 'h';//不能修改因为字符常量区是被写入到代码区的,而代码区不能被修改printf("read only char addr: %p\n",str);//已初始化全局变量区printf("init global value addr: %p\n",&init_gval);//所谓的静态区就是已初始化全局变量区static int a ;   printf("stack addr: %p\n",&a);//已初始化全局变量区printf("uninit global value addr: %p\n",&un_gval);//堆区char *heap1 = (char*)malloc(100);char *heap2 = (char*)malloc(100);char *heap3 = (char*)malloc(100);char *heap4 = (char*)malloc(100);char *heap5 = (char*)malloc(100);            printf("heap1 addr: %p\n",heap1);//向地址增大方向增长    printf("heap2 addr: %p\n",heap2);    printf("heap3 addr: %p\n",heap3);    printf("heap4 addr: %p\n",heap4);    printf("heap5 addr: %p\n",heap5);                                                                                                                   //栈区                 printf("stack1 addr: %p\n",&heap1);    printf("stack2 addr: %p\n",&heap2);printf("stack3 addr: %p\n",&heap3);    printf("stack4 addr: %p\n",&heap4);   printf("stack5 addr: %p\n",&heap5);//命令行参数int i = 0;for(;argv[i];i++){printf("argv[%d]:%p\n",i,argv[i]);}//环境变量for(i=0;env[i];i++){printf("env[%d]:%p\n",i,env[i]);}return 0;}

运行结果:

通过观察静态变量的位置,可以认为静态变量就是全局变量,只是静态变量只初始化一次,有作用域的限制。

这里栈区还有一个特点:我们平时定义结构体对象时,我们取地址都是返回整个结构体最低的地址,内部是使用低地址向高地址排列,使用的是起始地址加偏移量的访问方式,但是栈区整体还是先使用高地址在使用低地址。

那么这里就有一个问题了,这张图是真实的物理内存吗?

我们再来验证一下:

  #include <stdio.h>#include <stdlib.h>#include <unistd.h>int g_val = 100;int main(){pid_t id = fork();if(id==0){//子进程int cnt = 5;while(1){printf("child, pid:%d, ppid:%d, g_val:%d ,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);sleep(1);if(cnt == 0){g_val = 200;printf("child change g_val: 100->200\n");}cnt--;}}else {//父进程while(1){printf("father, pid:%d, ppid:%d, g_val:%d ,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);                                                   sleep(1);}}return 0;}

运行上面代码的结果:

什么意思呢?就是我们定义了一个全局变量 g_val,然后我们通过 fork() 创建了一个子进程,让子进程修改了全局变量。我们之前文章中提到过,因为进程之间要保证数据的独立性,父进程的数据子进程也要有一份,而Linux采用写时拷贝,所以在子进程没有修改全局变量值时,父进程和子进程的全局变量地址相同可以理解。但是子进程对全局变量做修改后,写时拷贝应该重新申请一块空间来存放修改后的值,但是根据运行结果我们发现地址还是相同的,子进程全局变量的地址并没有改变,同一个地址竟然读出不同的值?所以我们可以大胆推测我们看到的地址并不是真正的物理地址。

得出结论:

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

2.进程地址空间

2.1 操作系统如和将虚拟地址转换为物理地址

所以之前说“程序的地址空间”是不准确的,准确的应该说成 进程地址空间 ,那该如何理解呢?

每一个进程运行之后,都会有一个进程地址空间的存在!都要在系统层面都要有自己的页表映射结构

在C/C++中,变量在编译形成可执行程序后,就没有变量名的概念了,都是地址。

2. 什么是地址空间?什么是区域划分?

地址空间也要被OS管理起来!!每一个进程都要有地址空间,系统中,一定要对地址空间做管理。如何管理地址空间呢? 也是通过之前文章提过的先描述,在组织。所以地址空间最终一定是内核的数据结构对象,就是一个内核结构体。

在这个结构体中,分别有每个空间如栈区,堆区的开始和结束位置。

在Linux中,这个进程/虚拟地址空间的东西,叫做:struct mm_struct

struct mm_struct
{long code start;long code_end;long data_start;long data_end;long heap_start;long heap_end; long stack_start;long stack_end;// ...
}

进程PCB Linux 中的struct task_struct 中也是有指针指向mm_struct的。 

3.为什么要有地址空间

  1. 让进程以统一的视角看待内存,所以任意一个进程,可以通过地址空间+页表可以将乱序的内存数据,变成有序,分门别类的规划好,使得无序边有序
  2. 存在虚拟地址空间,因为页表中有访问权限字段,可以有效的进行进程访问内存的安全检查,比如我们无法修改字符常量的内容,是因为页表访问权限是只读。
  3. 将进程管理和内存管理进行解耦
  4. 通过页表让进程映射到不同的物理内存处,从而实现进程的独立性!所以每一个进程都认为自己可以使用4GB的空间,但是真实的物理空间只有4GB,一个进程并不知道其他进程的存在。
  5. CPU中也有一个CR3寄存器来保存页表的地址,这个地址是真实的物理地址。

扩展问题

我们如果在玩一些大型游戏时,游戏所需要的内存非常大,我们之前学习过 进程 = 内核数据结构体PCB+程序的代码和数据,我们把游戏加载到内存中时,是把所有的代码和数据都拷贝过来吗?根据我们呢的常识,显然不是这样的,因为我们得内存很小,为什么游戏还是可以运行的呢?因为页表中还有是否分配空间和是否有内容的字段,00,表示既没有分配空间也没有内容,我们游戏一次只加载一部分代码和数据,当CPU执行完这段代码时,要执行下面代码,操作系统就会将上面字段改为00,出现缺页中断,然后再去磁盘中拷贝接下来的代码和数据,释放执行完的代码和数据,这样就可以使得我们得游戏可以正常运行。

本篇结束!

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

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

相关文章

网络安全事件分级指南

文章目录 一、特别重大网络安全事件符合下列情形之一的&#xff0c;为特别重大网络安全事件&#xff1a;通常情况下&#xff0c;满足下列条件之一的&#xff0c;可判别为特别重大网络安全事件&#xff1a; 二、重大网络安全事件符合下列情形之一且未达到特别重大网络安全事件的…

前端实现一个时间区间内,再次单选功能,使用Antd组件库内日历组件Calendar

需求&#xff1a;需要先让用户选择一个时间区间&#xff0c;然后再这个时间区间中&#xff0c;让用户再次去单选其种特殊日期。 思路&#xff1a; 1.先用Antd组件库中日期选择DatePicker.RangePicker实现让用户选择时间区间 2.在选择完时间区间后&#xff0c;用这个时间区间…

从零开始 --- 创建vue项目

1、Vue脚手架创建项目 vue create home_vue 我选择了vue3 2、引入element-plus npm i element-plus vue2 对应 npm i element-ui main.js中 import { createApp } from vue import App from ./App.vue import ElementPlus from element-plus import element-plus/theme-…

Spring框架知识总结

目录 1、Spring框架有哪些设计模式&#xff1f; 2、介绍一下Spring框架和SpringBoot框架&#xff1f; 3、介绍一下SpringBoot具有哪些功能模块&#xff1f; 4、Spring用到了什么组件&#xff1f; 5、什么是IoC? 什么是AOP&#xff1f; 6、SpringBoot运行原理&#xff1…

鸿蒙HarmonyOS开发用什么语言

1.网上流行一句有中国底蕴的话&#xff1a;鸿蒙系统方舟框架盘古大模型。都方舟框架了肯定主推的是ArkUI框架。其实还能使用C、Java和Js开发。 2.从API8开始&#xff0c;Java语言已经从鸿蒙开发剔除了&#xff0c;而官方推荐的是ArkTs.下图是ArkTS与TS、JS的关系。 ArkTs 是TS的…

BFS:八数码问题求解

八数码原题 剖析一下BFS BFS算法是一种图遍历算法&#xff0c;它从起点开始&#xff0c;逐层扩展搜索范围&#xff0c;直到找到目标节点为止。 BFS算法一般选择队列作为节点存储的数据结构&#xff0c;我们将搜索目标节点的问题抽象为寻找目标状态&#xff0c;那么队列…

Vue3 reative回显问题

1. reactive 在做项目的时候通常会遇到这种情况&#xff0c;比如我们有一个 Table 显示数据&#xff0c;添加 Table 数据的时候使用 dialog 弹出&#xff0c;在里面填写字段然后添加。 在 vue3 中&#xff0c;对于对象的响应式定义推荐使用 reactive &#xff0c;那么可以写入…

运筹学经典问题(二):最短路问题

问题描述 给定一个图&#xff08;有向图或无向图&#xff09; G ( V , E ) G (V, E) G(V,E)&#xff0c; V V V是图中点的集合&#xff0c; E E E是图中边的集合&#xff0c;图中每条边 ( i , j ) ∈ E (i, j) \in E (i,j)∈E都对应一个权重 c i j c_{ij} cij​&#xff08;…

Android取消深色适配

从Android10&#xff08;API 29&#xff09;开始&#xff0c;在原有的主题适配的基础上&#xff0c;Google开始提供了Force Dark机制&#xff0c;在系统底层直接对颜色和图片进行转换处理&#xff0c;原生支持深色模式。当系统设置深色主题背景或者进入省电模式情况下会进入深色…

2023年烟花爆竹经营单位主要负责人证模拟考试题库及烟花爆竹经营单位主要负责人理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年烟花爆竹经营单位主要负责人证模拟考试题库及烟花爆竹经营单位主要负责人理论考试试题是由安全生产模拟考试一点通提供&#xff0c;烟花爆竹经营单位主要负责人证模拟考试题库是根据烟花爆竹经营单位主要负责人…

RGB颜色表示法(RGBA解释) 以及常见的色调

RGB&#xff1a;代表red&#xff0c;green&#xff0c;blue。即用这三个色调表示所有颜色。 表示方式如&#xff1a;&#xff08;255,255,255&#xff09;白色、&#xff08;0,0,0&#xff09;黑色 改变三个不同的数值可以得到不同的颜色&#xff0c;数值取值范围为0-255&#…

设计模式——模板方法模式

引言 模板方法模式是一种行为设计模式&#xff0c; 它在超类中定义了一个算法的框架&#xff0c; 允许子类在不修改结构的情况下重写算法的特定步骤。 问题 假如你正在开发一款分析公司文档的数据挖掘程序。 用户需要向程序输入各种格式 &#xff08;PDF、 DOC 或 CSV&#…

Ubuntu 常用命令之 cp 命令用法介绍

cp命令在Ubuntu系统中用于复制文件或目录。它的基本格式是cp [选项] 源文件或目录 目标文件或目录。 以下是一些常用的cp命令选项 -i&#xff1a;在覆盖目标文件之前将给出提示。-r或-R&#xff1a;递归复制&#xff0c;用于目录的复制操作。-v&#xff1a;详细模式&#xff…

2023-12-12 AIGC-AI工具的基本工作原理

摘要: 2023-12-12 AIGC-AI工具的基本工作原理 AI工具的基本工作原理 AI工具的基本工作原理涉及到一系列复杂的技术和算法。这些原理可以根据不同类型的AI工具进行概括&#xff0c;包括机器学习、自然语言处理、图像识别等。以下是一些关键的AI工具及其工作原理的概述&#xff…

对于实例控制,枚举类型优先于readResolve

实例控制是指控制类实例的创建和使用过程&#xff0c;而 readResolve 方法是 Serializable 接口中的一个特殊方法&#xff0c;用于在反序列化时控制对象的实例。在一些情况下&#xff0c;使用枚举类型可以更优雅地实现实例控制&#xff0c;而不需要依赖 readResolve 方法。 下…

网络基础(十二):ACL与NAT

目录 一、ACL 1、ACL的概述 2、ACL的分类 3、ACL的应用 4、ACL的组成和基本原理 ​编辑 5、ACL的配置 5.1配置基本ACL 5.2配置高级ACL 二、NAT 1、NAT的概述 2、NAT的分类 3、NAT的工作原理 4、静态NAT的配置 5、动态NAT的配置 6、NAPT&#xff08;端口映射&am…

查询某个类是在哪个JAR的什么版本开始出现的方法

背景 我们在依赖第三方JAR时&#xff0c;同时也会间接的依赖第三方JAR引用的依赖&#xff0c;而当我们项目中某个依赖的版本与第三方JAR依赖的版本不一致时&#xff0c;可能会导致第三方JAR的在运行时无法找到某些方法或类&#xff0c;从而无法正常使用。 如我正在开发的一个…

流程引擎相关资料

最近调研流程引擎相关知识&#xff0c;BPMN规范和流程引擎相关知识无法避开&#xff0c;以及市面上比较多的流程引擎产品。 BPMN2.0 基本形状 流对象&#xff08;Flow Objects&#xff09;&#xff0c;流对象是定义业务流程的主要图形元素。它进一步细分为三个类别&#xff0…

[SUCTF 2018]MultiSQL MYSQL 预处理写

首先这道题需要预处理写马 之前在ctfshow中学习过预处理 我们来看看 CTFSHOW -SQL 注入-CSDN博客 首先我们开始判断是否存在注入 2^(if(10,1,0))2^(if(ascii(mid(user(),1,1))>0,0,1))判断出存在sql注入 然后我们开始fuzz 发现 select &#xff0c;union 都没了 但是…

Mistral MOE架构全面解析

从代码角度理解Mistral架构 Mistral架构全面解析前言Mistral 架构分析分词网络主干MixtralDecoderLayerAttentionMOEMLP 下游任务因果推理文本分类 Mistral架构全面解析 前言 Mixtral-8x7B 大型语言模型 (LLM) 是一种预训练的生成式稀疏专家混合模型。在大多数基准测试中&…