Linux进程地址空间——上篇

2023-11-09

目录 

一. 前言:

二.进程地址空间

1.通过一个例子去初步的了解进程地址空间:

        使用VS写了一段代码:

        在Linux中使用vim编辑器写类似的代码:

 结果解析:

2.什么是进程地址空间?

举个例子大家就明白了画饼的意义:

如何画大饼?

3.详谈进程地址空间: 

 ​编辑

 进程地址空间的结构体源码:

 


一. 前言:

       当我们在学习C语言/C++的过程中,想必经常会在书中见过上面这副图吧,我想问问,大家眼中的这幅图代表着什么?

        其实这是个地址空间,从低到高,从下而上,有各个区域,例如:代码区、堆区、栈区、静态区等,有的同学会说:“这不就是计算机中的内存(物理)地址空间吗?我们写的代码数据被运行后都会加载进内存”。其实这块地址空间并不是内存,而是进程的虚拟地址空间,是每个进程专属拥有的空间!

二.进程地址空间

1.通过一个例子去初步的了解进程地址空间:

        使用VS写了一段代码:

 在该程序中,在局部中修改全局变量的值,并打印修改前后的变化。

        在Linux中使用vim编辑器写类似的代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>

int gloval=100;    //全局变量


int main(){
    pid_t id=fork();    //创建子进程
    if(id<0){
        printf("create process perror!");
        return -1;
            }

    //子进程执行流代码:
    else if(id==0){
        int cnt=0;
        while(1){
            printf("我是子进程,pid:%d ppid:%d,gloval:%d,gloval地址:%p\n",           
                              getpid(),getppid(), gloval,  &gloval);
            cnt++;
            if(cnt==10) gloval=300;
                }
            }

    //父进程执行流代码
    else{
        while(1){
          printf("我是父进程 , pid: %d , ppid: %d , gloval: %d , gloval地址: 
                 %p\n",getpid(),getppid(),gloval,&gloval);
          sleep(2); 
        }
    return 0;
    }

 运行结果:

 结果解析:

       1. 我们从代码中得知父进程的gloval为100,地址0x60105c,子进程的gloval和地址与父进程的一样,没问题,因为gloval是全局变量

        2.因为代码中用了fork函数(创建子进程,表示当前该程序中有两个执行流),父子进程各自执行各自的while循环代码,但是从绿框那部分的显示结果中可以发现:子进程在循环中对全局变量gloval进行修改,变为了300没问题,但是纵观父进程的执行结果来看,gloval却还是100,gloval既然是全局变量,那为什么父子进程在读取同一个地址/变量的过程中,双方怎么会出现不同的结果呢?

        按理说,gloval作为全局变量,子进程对其进行修改,那么父进程读取的就应该是gloval被修改过之后的值了(注gloval的地址从始至终没有变过,所以肯定不是变量的问题) 。

 那么根据这个结果,我们可以得出一个结论:

        之前我们在C/C++学习的过程中,从屏幕中打印出来的地址,绝对不是对应的物理地址,而叫做虚拟地址,那么上面的那个图所表示的也根本不是内存地址空间,而叫做虚拟地址空间。

        知识解析:任何我们学过的语言,C/C++/Java/Python等,从代码中获取变量/指针/函数地址都绝对不会是物理地址。虚拟地址是由操作系统提供的,既然是虚拟地址,那么一定有某种途径会将虚拟地址转化为物理地址,因为程序在被启动时数据和代码必须被加载到物理内存中,那么在内存中,代码中的各种变量和函数也就有了自己的物理地址——这是冯诺依曼体系所规定的,所以在加载到内存之前,肯定是将虚拟地址转换为物理地址,这里的转化工作由操作系统完成。

        


        

2.什么是进程地址空间?

        进程地址空间——又叫虚拟地址空间,就是从进程的视角去看地址空间,是进程运行时就用到的代码数据虚拟地址的集合。操作系统会给每个进程都创建一个独立的虚拟地址空间,而虚拟地址空间的大小与内存空间的大小相同(一般为4GB)。那为什么虚拟地址空间会和内存一样大呢?操作系统会给进程画大饼,让进程以为它可以使用整个内存的资源空间。

        每个进程总是认为自己是独占内存资源的,但其实只是操作系统画给进程的大饼,让进程相信自己是独占内存资源的,这样可以提升进程的使用效率。

举个例子大家就明白了画饼的意义:

        一个外国的富豪拥有十个亿的身价,这个富豪没有结婚已经年迈老矣,但在外面有3个私生子,其中有两个儿子被父亲安排到他手底下的公司去锻炼,大儿子是麾下某个工厂的老板,二儿子是金融公司的总经理,三儿子年龄比较小在大学读书。这三个私生子彼此并不知道其他两个的存在,富豪对自己的大儿子子勉励说:“你要积极上进,好好努力,为自己的未来做出业绩,等老爸以后走了,我的十亿遗产就全是你的了!” ;对二儿子也勉励说:“你要多向公司有经验的前辈汲取经验,把握好每一个项目的分寸,冷静思考,等老爸以后走了,公司就靠你了,我这几十年所获得的一切也就是你的了!”;对三儿子也勉励说:“你在学校好好读书,努力往上考到更高的地方,未来成为一名有名望的学者,这样一来老爸也就能了无遗憾,将一切托付给你了!”。

       所以从这三个私生子的视角来看,他们认为他们未来都能继承父亲的10亿家产,于是更加努力的为父亲手下的公司卖力,为公司赚更多的钱。 

     

        解析上面的结构图:大富翁的10亿财产就是操作系统,三个儿子就好比三个进程,这3个儿子问父亲要钱,就是进程占用内存的各种资源。    当大儿子问富翁要钱时,肯定不可能一下子问他爹要10亿,这是不可能给的并且也不现实,但问老爸要个10万美金还是可以的,老爸给了;同理二三儿子也是一样。某个进程申请要资源,操作系统也只是一点一点的给,因为还要满足其它进程的需求。

如何画大饼?

       画大饼,就是给你描绘一个美好的未来,给你描绘一幅蓝图,比如上面的故事中,富豪在画的大饼里应该包含着:饼是给谁的? 什么时候给?在什么条件下能给? 打算给多少钱?”所以把这些属性汇总起来就像是给每个私生子描绘的一幅蓝图,而这副蓝图这块大饼对应到计算机数据结构的对象,就形成了一个完整的结构体。


        并且他在画饼的同时也需要管理,富豪给3个私生子画饼,同时富豪也得对他自己画的饼进行管理吧:比如要记住哪个大饼对应的是哪个私生子,画的大饼是否需要随着私生子的成长而进行相对应的改变? 相对应的就是操作系统给每个进程提供的地址空间,每个进程地址空间里面的具体属性不相同,并且地址空间的属性能够动态改变。而操作系统对这些地址空间(大饼)也需要进行管理,那么就需要用到我之前讲到的操作系统的管理理念:先描述,再组织。


        对管理对象先进行描述,所以在Linux中地址空间的本质是内核中的一个结构体,名叫:          struct mm_struct{ }


3.详谈进程地址空间: 

 

经过上面的讲解,我们已经明白了在上面这个地址空间中共有4GB大小(和内存大小一样),是2的32次方个字节大小,而每个字节都表示一个地址,也就是说共有2的32次方个地址。

这2的32次方个地址都是虚拟地址,且每个地址是由32位bit位组成,从0x0000....0000到0xFFFF....FFFF由低到高。

案例验证:

 运行结果:

地址空间的组成涉及到区域的划分:

        举个例子,小学某个班中一个男生和一个女生做同桌,两人共用一张100厘米长的桌子,两人为了公平起见划定了三八线,各占桌子的一半长度。但是这个男生有些胖,导致他总是超出划定的范围,女生很苦恼,总是强调该男生,但他总是超了范围。于是她又规定两人双方各占45厘米,中间有10厘米的缓冲地带,但是该男生还是占到女生的课桌,女生彻底生气了,规定男生到最后只有30厘米的位置可用。

        从这个例子可知:桌子好比虚拟地址空间,男女生划的三八线就是在进行区域的划分

        基于此,进程地址空间中那些堆区、栈区、数据区、代码区也都有各自的区域划分: 

 进程地址空间的结构体源码:

未完待续......,接下来请看我写的下一篇博客! 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux进程地址空间——上篇 的相关文章

  • Capistrano 3 部署无法连接到 GitHub - 权限被拒绝(公钥)

    我使用 Capistrano v3 和 capistrano symfony gem 设置了以下部署脚本 我正在使用 Ubuntu 14 4 部署到 AWS EC2 实例 我正在连接从 AWS 下载的 pem 文件 我的deploy rb中
  • 为什么我可以在 /proc/pid/maps 输出中看到几个相同的段?

    测试在32位Linux上进行 代码如下 int foo int a int b int c a b return c int main int e 0 int d foo 1 2 printf d n d scanf d e return
  • 无法在 Perl 中找到 DBI.pm 模块

    我使用的是 CentOS 并且已经安装了 Perl 5 20 并且默认情况下存在 Perl 5 10 我正在使用 Perl 5 20 版本来执行 Perl 代码 我尝试使用 DBI 模块并收到此错误 root localhost perl
  • Linux 上的基准测试程序

    对于一项任务 我们需要使用不同的优化和参数来对我们的实现进行基准测试 有没有一种可行的方法可以在Linux命令行 我知道时间 上使用不同的参数对小程序进行基准测试 从而为我提供CSV或类似内容的时间数据 输出可能类似于 Implementa
  • 警告:请求的映像平台 (linux/amd64) 与检测到的主机平台 (linux/arm64/v8) 不匹配

    警告 请求的映像平台 linux amd64 与检测到的主机平台 linux arm64 v8 不匹配 并且未请求特定平台 docker 来自守护程序的错误响应 无法选择具有功能的设备驱动程序 gpu 我在 mac 上尝试运行此命令时遇到此
  • 当用户按下打印时运行脚本,并且在脚本结束之前不开始假脱机(linux,cups)

    我需要做的是结合用户按下打印来执行 python 程序 脚本 并且在该程序退出之前不要让打印作业假脱机 原因是打印驱动程序不是开源的 我需要更改用户设置 在本例中是部门 ID 和密码 通常是每个用户 但因为这是一个信息亭 具有相同帐户的不同
  • 限制 Imagemagick 使用的空间和内存

    我在 Rails 应用程序上使用 Imagemagick 使用 rmagick 但我的服务器 Ubuntu 不是很大 当我启动转换进程时 Imagemagick 占据了我的服务器 30GB HDD 的所有位置 内存 我想限制内存和 tmp
  • 后台分叉无法正常工作[重复]

    这个问题在这里已经有答案了 我运行这个程序 在前景和背景中 int main int pid printf App Start pid d n getpid while 1 pid fork if pid 0 printf Child n
  • 捕获数据包后会发生什么?

    我一直在阅读关于网卡捕获数据包后会发生什么的内容 我读得越多 我就越困惑 首先 我读过传统上 在网卡捕获数据包后 它会被复制到内核空间中的一个内存块 然后复制到用户空间 供随后处理数据包数据的任何应用程序使用 然后我读到了 DMA 其中 N
  • X11 模式对话框

    如何使用 Xlib 在 X11 中创建模式对话框 模态对话框是一个位于应用程序其他窗口之上的窗口 就像瞬态窗口一样 并且拒绝将焦点给予应用程序的其他窗口 在 Windows 中 当试图从模态窗口夺取焦点时 模态也会通过闪 烁模态窗口的标题栏
  • PyPI 上的轮子平台约束有什么限制吗?

    是否有任何地方 PEP 或其他地方 声明关于 Linux 轮子上传范围的限制 PyPI http pypi io 应该有 具体来说 上传是否被认为是可接受的做法linux x86 64轮子到 PyPI 而不是manylinux1 x86 6
  • 从c调用汇编函数

    我试图从 c 调用汇编函数 但我不断收到错误 text globl integrate type integrate function integrate push ebp mov esp ebp mov 0 edi start loop
  • Linux“屏幕”的 Windows 等效项还是其他替代方案?

    我正在寻找一种在 Windows 环境中控制程序的方法 我希望它与 Linux 软件有点相似 screen 我搜索的原因是我需要使用标识符启动一个程序 在 Windows 上 这样我以后就能够关闭该特定程序 而无需关闭其他任何程序 即使实际
  • 用于编辑 /etc/sudoers 文件的正则表达式模式

    我想删除 etc sudoers 文件中的 uncommnet 轮组 那么我应该使用什么正则表达式模式 cat etc sudoers Allows members of the sys group to run networking so
  • 如何在gnuplot中将字符串转换为数字

    有没有办法将表示数字 以科学格式 的字符串转换为 gnuplot 中的数字 IE stringnumber 1 0e0 number myconvert stringnumber plot 1 1 number 我可能使用 shell 命令
  • 如何确定代码是否在信号处理程序上下文中运行?

    我刚刚发现有人正在从信号处理程序调用我编写的绝对不是异步信号安全的函数 所以 现在我很好奇 如何避免这种情况再次发生 我希望能够轻松确定我的代码是否在信号处理程序上下文中运行 语言是 C 但该解决方案不适用于任何语言吗 int myfunc
  • C++:Linux平台上的线程同步场景

    我正在为 Linux 平台实现多线程 C 程序 其中我需要类似于 WaitForMultipleObjects 的功能 在搜索解决方案时 我发现有一些文章描述了如何在 Linux 中实现 WaitForMultipleObjects 功能
  • 如何重命名 .tar.gz 文件而不提取内容并在 UBUNTU 中创建新的 .tar.gz 文件?

    我有一个命令将创建一个新的 tar gz现有文件中的文件 sudo tar zcvf Existing tar gz New tar gz 该命令将创建一个新的New tar gz从现有的文件Existing tar gz file 谁能告
  • 在 Linux 控制台中返回一行?

    我知道我可以返回该行并用以下内容覆盖其内容 r 现在我怎样才能进入上一行来改变它呢 或者有没有办法打印到控制台窗口中的特定光标位置 我的目标是使用 PHP 创建一些自刷新的多行控制台应用程序 Use ANSI 转义码 http en wik
  • 提高mysql导入速度[关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我有一个很大的数据库22GB 我曾经用过进行备份mysqldumpgzip 格式的命令 当我提取 gz 文件时 它会生成 sql文件的

随机推荐

  • python读取、显示、保存图片

    一 opencv 读 cv2 imread path mode 读取出来是ndarray 如果是读取灰度图 需要指定颜色模式为cv2 IMREAD GRAYSCALE 这样读取出的是一个二维数组 而不是彩色图像的三维数组 如果读取彩色图像
  • ps2023如何导出svg

    在 文件 文件 导出首选项 里勾选 使用旧版导出为 就可以在图层里右键导出svg啦 否则切图也导不出svg 右键导出为里面的格式也没有svg选项 官方建议使用以下解决方案 https helpx adobe com photoshop us
  • windows配置git公钥,读写远程git项目

    首先Windows电脑需要下载并安装git 从官网直接下载然后安装即可 https git scm com download win 添加公钥 ssh keygen t rsa C xxxxx xx com 注意 这个xxxxx xx co
  • Hadoop是小象——Hadoop集群安装配置

    文章目录 所需软件 集群网络配置 集群SSH免密登陆设置 Hadoop安装配置 所需软件 Linux所需软件包括 JavaTM1 5 x 必须安装 建议选择Sun公司发行的Java版本 以前安装过 ssh 必须安装并且保证 sshd一直运行
  • 不认识的东西

    typedef struct 1 struct定义一个结构体 2 typedef给这个结构体改一个名字 typedef struct student Student Student就是这个结构体修改后的名字
  • 数据结构——单链表的实现(c语言版)

    前言 单链表作为顺序表的一种 了解并且熟悉它的结构对于我们学习更加复杂的数据结构是有一定意义的 虽然单链表有一定的缺陷 但是单链表也有它存在的价值 它也是作为其他数据结构的一部分出现的 比如在图 哈希表中 目录 1 链表节点的结构 2 头插
  • cublas_v2.h: No such file or directory

    caffe正常编译了 但是另外一个工程中使用caffe时显示 cublas v2 h No such file or directory 直接在该工程的cmakelist文件中加入 INCLUDE DIRECTORIES usr local
  • Git Pull 错误

    当是用TortoiseGit 从多个源 Pull过数据后 不能再使用默认的 Remote origin选项进行Pull操作 每个工程 Commit Push前需要Pull操作时 采用独立的URL 即 下面的选项 Arbitrary URL
  • Activiti进阶(九)——接收任务(ReceiveTask)

    转载地址 http blog csdn net zjx86320 viewmode contents 接收任务 ReceiveTask 即等待任务 接收任务是一个简单任务 它会等待对应消息的到达 当前 官方只实现 了这个任务的Java语义
  • HwBinder驱动篇-Android10.0 HwBinder通信原理(十)

    Android取经之路 的源码都基于Android Q 10 0 进行分析 Android取经之路 系列文章 系统启动篇 Android系统架构Android是怎么启动的Android 10 0系统启动之init进程Android10 0系
  • 解决maven配置报错:The JAVA_HOME environment variable is not defined correctly(亲测有效)

    显然是环境变量的问题导致的 1 对于初学者而言 建议配置两个maven环境变量 2 添加至path 变量值是 MAVEN HOME bin M2 HOME bin 3 进入cmd 输入mvn v进行测试 如果是下面这样 说明就成功了 4 如
  • pytorch的语义分割------数据增广

    官方文档 https pytorch org docs stable torchvision transforms html highlight torchvision 20transforms 20functional module to
  • maven编译项目抛出out of memory

    是java堆内存过小的原因造成的 新增环境变量 MAVEN OPTS Xmx512m 问题解决
  • 【融职培训】Web前端学习 第11章 微信开发5 微信支付

    一 概述 如果需要实现微信支付功能 需要有一个已认证的微信服务号 并且开通微信支付 开通后微信会提供一个商户ID 有了这个ID才能成功调用微信支付接口 开通微信支付后 需要在微信支付后台 产品中心 gt 开发配置 中配置 JSAPI支付授权
  • 不小心在服务器上删了文件怎么恢复出厂设置,文件删除了怎么恢复?这样才能彻底清除彻底清除...

    现在人换手机就像换衣服 虽然不是一天一换 但大多数人一年一换已经成为常态 所以闲置的旧手机也越来越多 一般旧手机大家都是闲置 或者二手转卖 或是送给别人使用 如此一来 旧手机上各种数据就需要彻底清除 否则旧手机上个人信息一旦泄露 很可能会给
  • HTML教程

    第一章 HTML标签 网页格式 html 网页的开始与结束 body 网页的主体部分 显示在网页中用户可以浏览到的内容 head 网页的头部 大部分不显示在用户浏览界面 meta 网页的摘要信息 不会显示在浏览器浏览界面 title 网页标
  • 人工智能-Tansformer-全套讲解15-20章

    第21章 基于Bayesian Theory的MRC文本理解基础经典模型算法详解 1 Bayesian prior在模型训练时候对Weight控制 训练速度影响等功能详解 2 Bayesian prior能够提供模型训练速度和质量的数学原理
  • angular指令心得(ng-model)

    angular指令心得 ng model 在项目中编写指令 常常会依赖其他的指令来实现想要达到的功能 其中最常用到的便是ng model 它为我们明确了需要绑定的属性 虽然在指令中可以通过通过使用独立作用域的 来进行双向绑定 但使用ng m
  • 华清远见学习笔记—Level1—Day1—必备Linux命令和C语言基础

    本专栏为个人在华清远见嵌入式linux学习期间的笔记 希望能与各位读者共同进步 文章目录 前言 一 环境安装 1 Linux文件系统是树形结构 弱分区 重文件 2 常用EXT4分区格式 3 基础分区 二 文件和目录相关命令 1 嵌入式开发基
  • Linux进程地址空间——上篇

    目录 一 前言 二 进程地址空间 1 通过一个例子去初步的了解进程地址空间 使用VS写了一段代码 在Linux中使用vim编辑器写类似的代码 结果解析 2 什么是进程地址空间 举个例子大家就明白了画饼的意义 如何画大饼 3 详谈进程地址空间