当前位置: 首页 > news >正文

Linux->进程地址空间

目录

前言:  

1. 程序地址空间回顾

2. 进程空间是什么

3. 进程地址空间与内存

4. 进程地址空间和内存的关联

5. 为什么要有进程地址空间


前言:  

        我们在平时学习的过程当中总是听到栈、堆、代码段等等储存空间,但是这些东西到底是什么,我们又怎么理解呢?本篇就为大家解惑。

1. 程序地址空间回顾

         相信大伙们对于这张图片还是很熟悉吧,特别是对于堆和栈这一片区域,堆向上延伸,栈向下扩展,基本上是共同使用这一片空间。这片空间这样使用主要是服务于我们的动态库

        如果大伙想要验证这一张图片的正确性,可以自己验证一下,低地址代码地址长度更小,高地址更大。代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
#include<stdlib.h>int global_uval;									//全局变量未初始化
int global_val = 1;									//全局变量初始化int main(int argc, char* argv[],char* envp[])
{const char* point = "hello world";				//栈内指针和常量区字符串char* heap = (char*)malloc(100);				//栈内指针和堆区空间printf("代码区起始地址:        %p\n", main);printf("常量区字符串:          %p\n", point);printf("全局变量初始化:        %p\n", &global_val);printf("全局变量未初始化:      %p\n", &global_uval);printf("堆区地址:              %p\n", heap);printf("栈区地址:              %p\n", &point);printf("命令行参数:            %p\n", argv[0]);printf("环境变量:              %p\n", envp[0]);return 0;
}

         Linux下可以看到地址空间的变化逐渐增加,也正好对应了我们的地址空间的图。

         但是同样的代码在vs下却运行出了不同的结果,如下:

         仔细看vs下运行堆区地址和栈区地址大小与Linux下运行相反,具体原因我也不是很清楚,博主在这里也疑惑了半天,估计是vs悄悄的改了一些实现方法。

2. 进程空间是什么

        看了上面的解释也没有理解,啥是进程地址空间?博主知道你很急,但是你先别急,什么?非要看?好吧,请看下方结论:

进程地址空间不是真实物理地址而是虚拟地址

        知道了吗?没看懂是不?这就对了,还是等我徐徐道来。

        请先看下方代码:

        利用fork创建了一个子进程,count用于计数,当循环走过两次时,a被修改为100

  1 #include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 5 int main()6 {7   int a = 100;8   int count = 0;9   pid_t res = fork();    //创建一个子进程                                                                                    10 11   while(1)12   {13     if(res == 0)14     {15       printf("我是一个子进程,a = %d,    &a = %p\n",a,&a);16       sleep(1);17     }18     else{19       if(count == 2)20         a = 200;21       printf("我是一个父进程,a = %d,    &a = %p\n",a,&a);22       count++;23       sleep(1);24 25     }26   }27 28 29   return 0;30 }

         运行结果如下:

         上图中大家有发现什么不对的地方吗?首先,变量a定义在两个进程分流之前,那么父子进程应该拿到的是同一块数据,通过查看地址,再对应值,确实如此,但继续往下看,当计数两次之后,我们将父进程的a修改了,父进程的a也确实被更改了值,但是,父子进程拿到了同一块数据,为什么子进程的a没有被改变呢?更离谱的是它们两个的地址竟然一模一样,这合理吗?这很不合理。

        根据我们学习语言所知,同一块空间只能只能存一个数据,这里竟然存了两个数据,那么根据理论而言,我们能够分析出,我们获取到的地址不可能是真实的物理地址,而是虚拟地址。

         但是根据我们学习的计算机体系结构可以知道,任何一个磁盘上的内容想要跑到CPU中被运行,必须经过被载入内存这一过程,但是上面又显示我们拿到的不是真实的物理地址,就不可能是再内存当中的,难道是我们的冯诺依曼体系在这里出错了?很明显不可能,所以只有一种可能,那就是我们在程序中获取到的地址与我们的内存之间有联系

3. 进程地址空间与内存

        这一部分有些抽象,所以我先为大家讲一个故事吧。(这个故事是博主去别人哪里copy的,博主认为十分生动形象)。

        咱们在学校总是经历过划分三八线这种事情吧。就是给桌子划分区域,假设有小明和小妞两个人,他们有自己的区域,不能越过区域,到别人的领域去。如下:

         我们可以想一下,他们是怎么区分他们自己的区域的呢?不就是记录自己区域的起始结束位置嘛,也就是说小妞想要表示自己的位置,那就是如下:

struct xiaoniu_area{

        size_t begin = 0;

        size_t end = 50;

};

         小明也是同理,也就是说他们自己知道这一片空间的所属就行,不过呢,小明和小妞关系很好,可以亲亲抱抱的那种,所以这一条三八线也就是当作一个提醒罢了。所以呢,小妞有一天要画画,她需要更大的位置操作,那么她就向小明说,我想要多一点点位置,之后还你,小明说:“反正现在我也不用,你用吧”。这样小妞的位置就变为了如下:

struct xiaoniu_area{

        size_t begin = 0;

        size_t end = 70;

};

         那么,相对的小明的位置就被缩减了,图如下:

         看到上面的图,大伙有没有将我们的地址分配图联系起来呢?我们的进程地址也就是通过这个方式表示的,就像是我们的栈、堆等等,它的位置都是能够被调整的

        在Linux当中有一个struct mm_struct这样的结构体,用于表示各个区所对应的位置。如下:

struct mm_struct
{

    //代码区
    unsigned long code_start;
    unsigned long code_end;

   //堆区
    unsigned long heap_start;
    unsigned long heap_end;
    //栈区
    unsigned long stack_start;
    unsigned long stack_end;
}

         也就相当于整个进程地址空间的使用被这样一个结构体划分的明明白白。

        但是这又跟我们的内存有什么联系呢?别着急,接着看。

        我先给出结论:

每个进程都可以独占整个内存空间

         怎么理解上面这句话呢?咋一看是不是感觉很奇怪?仔细一看更奇怪了是不?

        我还是举一个例子。

        有一个10亿家产的富豪,他有2个私生子,这两个私生子不知道彼此的存在,此时呢,富豪对两个孩子分别说了,只要我寄了,这10亿就是你的了,所以呢,这两个还是都认为这10亿自己稳得了。这时,大儿子说,老爸,我想要20万买个车上班,富豪说,行,好好加油,之后小儿子又说,老爸,给我5个亿,我要单开一家公司,做大做强,富豪转身就抽出了七匹狼,你要皮带不要?小儿子就跑了。但是对于大儿子和小儿子来说,他们认为这10还是自己得吗?肯定是啊。

        这里的富豪就是操作系统,10亿就是内存,而两个儿子就是进程,他们可以向操作系统申请空间,操作系统也可以拒绝他们的请求,但是他们能得到的空间是内存大小的空间。这也就表明了,每一个进程都认为自己是可以独占内存的,但是操作系统是能够自己判断是否给你这么多

4. 进程地址空间和内存的关联

进程地址空间通过页表和内存关联起来。

         什么是页表?

        页表就是:进程将自己的代码和数据首先放在虚拟地址空间的对应的区域,在这其中会有一种表结构,叫做页表,页表的核心工作就是完成虚拟地址到物理地址之间的映射,最终我们的可执行程序的代码和数据可以加载到物理内存的任意位置,因为最终只需要建立代码和数据与物理内存之间的映射关系,就可以通过虚拟地址找到物理内存的对应地址。

        咱们可以想到每一个进程都是独立的,父子进程也是不例外的,那么每一个进程也都有属于知道的页表去对应真实的内存。看到这里,想必大家也能回到之前父子进程不同值,地址相同得问题了吧。那就是父子进程得虚拟地址相同,但是这个虚拟地址存在于两张页表当中,这两个页表通过相同的虚拟地址却映射了两个内存空间。

        那么,这两个映射不会映射到一个空间吗?

        不会,还记得我之前讲的mm_struct结构体,内存将这些空间用结构体划分了起来,并且划分之后还会标识这片区域已经被某个进程使用了,那么页表就知道了这篇空间不能使用了,它就会换一片区域去映射。如下:

         看到上面的图,我们可以认为父子进程是完全独立的吗?

        其实不能,因为我们的操作系统是十分会节省空间的,也就是当父进程或子进程的数据没有被改变的时候,两个页表指向的真实空间也是相同的,只有在数据发生改变的时候操作系统会为这一个空间开辟一个新的空间,然后对应给页表,但是页表的虚拟内存没有改变。这一过程被称为写时拷贝

5. 为什么要有进程地址空间

        我们使用malloc时,操作系统在我们申请内存的时候并没有直接的给我们那一片地址,但是这一片空间并不能被其他的进程使用,该片地址会处于一个闲置状态。这篇地址不能使用是这一个进程不能使用,而是其它进程可以使用,但是操作系统会保证数据不会冲突。

        也就是说,我们能够获取到虚拟地址,但是我们没有在意到底有没有实际的物理地址在哪里,反正我们要使用的时候,操作系统能给我们就是了。所以这样做就让我们的进程管理和内存管理之间解耦了。

        还有就是当操作系统要加载一个很大的程序,比如32个G,这样一个程序一定是不可能全部运行起来的,所以操作系统会慢慢的加载,没有被使用的部分就被先睡眠起来了。我们唯一的感受也就是程序变慢了。

        并且,通过进程地址空间,我们操作系统能够清楚地知道你写的进程是否正确,有没有越界?如果越界了,那么操作系统就会让你的进程崩溃,因为你的指针或者其它数据指向了其它进程的区域,保证了进程之间的独立性和安全性。


        以上就是我对进程地址空间的全部理解咯,有问题请帮忙指出啦,博主也是努力进步当中,哈哈。

相关文章:

Linux->进程地址空间

目录 前言&#xff1a; 1. 程序地址空间回顾 2. 进程空间是什么 3. 进程地址空间与内存 4. 进程地址空间和内存的关联 5. 为什么要有进程地址空间 前言&#xff1a; 我们在平时学习的过程当中总是听到栈、堆、代码段等等储存空间&#xff0c;但是这些东西到底是什么&…...

【奶奶看了也不会】AI绘画 Mac安装stable-diffusion-webui绘制AI妹子保姆级教程

1.作品图 2.准备工作 目前网上能搜到的stable-diffusion-webui的安装教程都是Window和Mac M1芯片的&#xff0c;而对于因特尔芯片的文章少之又少&#xff0c;这就导致我们还在用老Intel 芯片的Mac本&#xff0c;看着别人生成美女图片只能眼馋。所以小卷这周末折腾了一天&#…...

基于stm32电梯管理系统设计

基于stm32电梯管理系统设计这里记录一下以前自己做的嵌入式课程设计&#xff0c;报告中的图片和文字太多了&#xff0c;全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156&#xff0c;也可在微信公众号 *高级嵌入式软件* 里回复 *电梯* 查看完整版文章摘要关键…...

Spring中的FactoryBean 和 BeanFactory、BeanPostProcessor 和BeanFactoryPostProcessor解析

文章目录FactoryBean 和 BeanFactory后置处理器BeanPostProcessor 和 BeanFactoryPostProcessorBeanPostProcessorBeanFactoryPostProcessorFactoryBean 和 BeanFactory BeanFactory接⼝是容器的顶级接⼝&#xff0c;定义了容器的⼀些基础⾏为&#xff0c;负责⽣产和管理Bean的…...

【C++从入门到放弃】类和对象(上)

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《C从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 类和对…...

什么牌子的蓝牙耳机便宜好用?四款高品质蓝牙耳机推荐

随着时代的发展&#xff0c;蓝牙耳机的使用频率越来越高&#xff0c;不少人外出时除了带手机外&#xff0c;蓝牙耳机也成为了外出必备的数码产品之一。现在的蓝牙耳机品牌众多&#xff0c;什么牌子的蓝牙耳机便宜好用&#xff1f;下面&#xff0c;我来给大家推荐四款高品质的蓝…...

eddsa 算法

信息安全课程设计&#xff1a;eddsa 算法 一、项目要求 使用 C 语言开发&#xff1b;可以实现公私钥生成、签名、认证&#xff1b;只需要手动输入明文&#xff0c;代码会自动生成公私钥、签名、认证&#xff1b;记录公私钥生成、签名、认证的时间&#xff1b;在 VS 上运行&am…...

Xcode Developer Document 开发者文档

总目录 iOS开发笔记目录 从一无所知到入门 文章目录IntroDeveloper Documentation 打开方式菜单栏点击 &#xff5c; 快捷键方式另一种打开方式Intro 2016年我在学校学Java的时候&#xff0c;要查某个Java类/方法的用法还得自己手动下载一种.chm格式的开发文档文件&#xff0c…...

IntelliJ插件开发教程之新建项目

JetBrains公司系列产品IDEA、WebStrom、PyCharm、CLion、GoLand等都是基于IntelliJ Platform开发而成&#xff0c;掌握IntelliJ插件开发技能便能拥有提升开发效率的终极武器。本教程Demo源码请微信公众号“开发效率”进行获取。阅读原文如果您是JetBrains产品的用户&#xff0c…...

解决SpringBoot中@RequestBody不能和Multipart同时传递的问题

问题描述 今天在做文件上传的时候&#xff0c;遇到了这么一个错误日志&#xff1a; Resolved[org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘multipart/form-data;boundary--------------------------771899451541318130280588;charsetUTF-8’…...

【华为OD机试模拟题】用 C++ 实现 - 统计匹配的二元组个数(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明统计匹配的二元组个数题目输入输出描述示例一输入输出说明示例二输入输出说明备注Code使用说明 参加华为od机试,一定要注意不要完全背诵代码&...

Vuex 面试题总结 的历史汇总!

一.vuex是什么&#xff1f;怎么使用&#xff1f;哪种功能场景使用它&#xff1f; Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。简单来说就是&#xff1a;应用…...

Redis缓存更新策略与缓存穿透、雪崩等问题的解决

文章目录一、缓存更新策略1、三种策略2、策略选择3、主动更新的方案二、缓存存在的问题1、缓存穿透2、缓存雪崩3、缓存击穿三、解决缓存问题1、自定义分布式锁2、解决缓存穿透问题3、解决缓存击穿问题一、缓存更新策略 1、三种策略 内存淘汰&#xff1a;redis自带的内存淘汰机…...

OSI和TCP/IP网络模型细讲

文章目录一、OSI七层参考模型二、TCP/IP体系结构三、TCP/IP参考模型四、沙漏计时器形状的TCP/IP协议族五、两种国际标准对比相似之处不同之处一、OSI七层参考模型 OSI参考模型共分为7层&#xff0c;低三层面向通信&#xff0c;可用软硬件实现&#xff1b;高三层面向信息处理&am…...

【正点原子FPGA连载】第十九章FreeRtos Hello World实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十九章FreeRto…...

php mysql高校田径运动会成绩管理系统

第一章 引言 1 1.1 选题背景 1 1.2 编写目的 2 1.3 目标 2 1.4 功能需求 3 第二章 开发工具介绍 4 2.1 PHP 4 2.2 APACHE 5 2.3 MYSQL数据库 5 2.4 运行环境 WINDOWS XP 6 2.5 XAMPP 6 2.6 DREAMWEAVE8 6 2.7 EDITPLUS 7 第三章 需求…...

scrum敏捷项目管理软件三款

Leangoo领歌Leangoo是国产的一个项目管理软件&#xff0c;www.leangoo.com &#xff0c; 专门的Scrum敏捷开发工具&#xff0c;看板的管理方式&#xff0c;高度可视化。它支持敏捷开发全流程。从产品路线图-需求-迭代-缺陷-测试-上线。燃尽图&#xff0c;工作量&#xff0c;迭代…...

【项目设计】高并发内存池(二)[高并发内存池整体框架设计|threadcache]

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…...

西电编译原理期末核心考点汇总(期末真题+相关知识点)

文章目录前言一、正规式1.1 相关知识点1.1.1 正规式定义1.1.2 辅助定义1.2 历年真题二、二义文法2.1 相关知识点2.1.1 二义性概念2.2 历年考题三、全部短语、直接短语和句柄3.1 相关知识点3.1.1 短语&#xff0c;直接短语和句柄定义3.1.2 短语&#xff0c;直接短语和句柄例题3.…...

追梦之旅【数据结构篇】——详解C语言实现二叉树

详解C语言实现二叉树~&#x1f60e;前言&#x1f64c;什么是二叉树&#xff1f;二叉树的性质总结&#xff1a;整体实现内容分析&#x1f49e;1.头文件的编写&#xff1a;&#x1f64c;2.功能文件的编写&#xff1a;&#x1f64c;1&#xff09;前序遍历的数值来创建树——递归函…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...