[Linux打怪升级之路]-秒懂进程地址空间

news2024/10/2 1:24:53

前言

作者:小蜗牛向前冲

名言:我可以接受失败,但我不能接受放弃

如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。

目录

一、C/C++下的地址空间

1、回忆C/C++下的内存分布

2、看一个现象

二、虚拟地址空间

1、浅谈虚拟地址空间

2、图解进程空间


本期学习目标:了解C/C++下的地址空间,操纵系统下的进程地址空间

我们在学习进程地址空间的时候,要先回忆一下C/C++下的地址空间。

一、C/C++下的地址空间

1、回忆C/C++下的内存分布

查看源图像       我们在学习C/C++的时候常说全局变量和局部变量存在数据段,只读常量的数据存在代码段,自己也可以为变量的申请空间我们称为堆区,还有一个区域就做栈区主要存放函数的返回值/函数的参数/非静态的成员变量。但是我们常常说这就是计算机内的内存分布,但他们真的就是指磁盘中的内存分布吗?我们要内存是直接在磁盘在申请的吗?

在回答这些问题之前我们先在Linux下跑一段代码,见见一个难以理解的现象。

2、看一个现象

我们写一个代码,用fork创建子进程,并循环打印子进程和父进程,让子进程和父进程都先打印出

 global_value的值和 global_value的地址,当cet==5的时候,子进程改变 global_value的值为300,父进程不变,观察子进程和父进程的变化。

#include <stdio.h>
#include <unistd.h>


int global_value = 100;

int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        printf("fork error\n");
        return 1;
    }
    else if (id == 0)
    {
        int cnt = 0;
        while (1)
        {
            printf("我是子进程, pid: %d, ppid: %d | global_value: %d, &global_value: %p\n", getpid(), getppid(), global_value, &global_value);
            sleep(1);
            cnt++;
            if (cnt == 5)
            {
                global_value = 300;
                printf("子进程已经更改了全局的变量啦..........\n");
            }
        }
    }
    else
    {
        while (1)
        {
            printf("我是父进程, pid: %d, ppid: %d | global_value: %d, &global_value: %p\n", getpid(), getppid(), global_value, &global_value);
            sleep(2);
        }
    }
    sleep(1);
}

这里我们发现一个很奇怪的现象为什么我们子进程global_value的值明明变为了300但是他的地址确实和100的地址是一样的。这是为什么?

如果我们继续按照在C/C++上进行理解,指针指向的地址空间是唯一的。这就显然和这里的结果相矛盾一个相同的地址这么可能存放相同的值。这说明这里的指针绝对指向的不是物理地址,要解释这个现象我们就不得不继续往下学习虚拟地址空间。

二、虚拟地址空间

1、浅谈虚拟地址空间

什么是虚拟地址空间呢?我相信有许多人都会有疑惑为什么会出现虚拟地址空间怎么个东西,这个问题下面会回答。但在此时我们要形成一个共识:一个进程会认为他独占系统资源(实际上并不是如此)。

我们都知道在C/C++的理解下,我们都认为有一块空间里面存放我们要执行的代码,但是在一个系统中不可能仅仅只有一个进程都在运行,那么也就说进程可能都把他们的要存储的内容分配到同一个空间中(因为进程们都认为,独占空间),那怎么显然会出错,但是在同一个系统中仍然存在多个进程同时在运行。那系统是怎么解决这个问题的呢?

其实我们由此也可得出每个进程都有自己的内存空间,但是真正的空间分布是由操作系统完成的,而那个进程自己的空间,我们称为进程地址空间(也就是虚拟地址空间)。

那么问题来,这个进程空间是怎么规划空间的呢?

我们要管理一个进程都是:先描述,在组织

一个进程的空间他的基本大小空间是字节,我们拿32位的机器来下,将能形成2^32的编码,每个编码都是一个地址,也就形成了4G的空间。对于PCB来说有存一个指针,指向一个结构体的struct mm_struct,而这个结构体内就规划了各个空间的起始地址和终止地址。

struct mm_struct
{
	//代码区
	size_t code_start, code_end;
	//数据段
	size_t data_start, data_end;
	//堆区
	size_t heap_start, heap_end;
	//栈区
	size_t stack_start, stack_end;
};

 这样各个内存的区域就描述好了,我们就可以通过PCB中的指针管理这个结构体从而管理进程地址空间。

2、图解进程空间

 从上面图我们看到了什么?

当我们执行my.exe文件的时候,首先是从磁盘中把要执行的代码导入到内存中,pcb就会所到my.exe要执行的指令,就会通过mm*指针让进程地址空间为my.exe分配好空间,在通过一个叫页表的结构和物理内存沟通,在真正的物理内存开好相应的空间。

从上面我们就知道以前我们说指针指向的内存空间,其实是虚拟地址空间。

理解了什么是进程地址空间,下面我们就解释一下为什么会出现我们前面讲的这个现象。

我们子进程global_value的值明明变为了300但是他的地址确实和100的地址是一样的。 

 在global_value为变为300的时候,进程物理空间的指向是上图,这里简单解释一下:子进程是以父进程的模板生成的,所以他最初进程空间通过页表和物理内存的联系都应该是一样的,这也就导致子进程和父进程的global_value的地址都是一样的,但是当我们通过子进程改变global_value的值而父进程不变时。就会发现下图的变化:

 这里我们明白:进程具有独立性。这就要求子进程的改变不能影响父进程。

这时就操作系统就会发生写时拷贝,为子进程的global_value重新在物理内存开辟一块空间给他进行存储,但是进程空间中的地址并没有发生改变,只是子进程的页表的映射改变了,指向了300的空间地址。

而我们对global_value取地址仅仅是得到的是进程空间的地址,这也就导致了为什么二个不同的值存储的空间会一样。

写时拷贝:父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本,后在让进程改变。

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

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

相关文章

【GIT】常用操作总结

一、在本地仓库及远程仓库创建分支&#xff0c;并建立关联关系。 1、创建本地分支&#xff0c;如图&#xff1a; 2、填写分支名称&#xff0c;勾选Checkout branch&#xff1a; 3、提交本地分支到远程分支&#xff1a; 右键选择Git -- Repository -- push&#xff1a; push的时…

Python爬取的网页,需要解码怎么办

前言 本文是该专栏的第26篇,后面会持续分享python的爬虫干货知识,记得关注。 很多时候,在用爬虫采集数据的时候,采集到的源码内容并非我们想要的正确信息,使用正则或者Xpath匹配到的信息也需要我们再次解码才能拿到精准的数据。最近也正是球迷朋友们非常关注卡塔尔世界杯…

[操作系统笔记]基本分段存储管理

内容系听课复习所做笔记&#xff0c;图例多来自课程截图 分段原理 与“分页”最大的区别就是&#xff1a;离散分配时所分配地址空间的基本单位不同 分页是不管程序的逻辑的&#xff0c;规定了页大小就是这么多&#xff0c;但是分段是依据程序自身逻辑来划分的&#xff08;分页的…

micro-app-源码解析4-数据通信篇-终篇

沙箱篇官方讲解地址 https://github.com/micro-zoe/micro-app/issues/21 1. 带着问题进行阅读 在做框架的时候&#xff0c;没法避免的遇见父子通信和兄弟通信的问题&#xff0c;但是如何实现通信这是个每个框架需要解决的问题。1.1 如何选择父子通信的方式 最好的方式应该是…

IOC操作Bean管理(基于注解方式)

IOC 控制反转&#xff0c;把创建对象过程交给Spring进行管理。 目录 什么是注解 Bean 管理注解方式&#xff08;创建对象&#xff09; 基于注解方式实现对象创建 第一步&#xff1a;引入依赖 第二步&#xff1a;开启组件扫描 创建类&#xff0c;在类上面添加创建对象注解…

Python爬虫实战,request+Matplotlib模块,Python绘制一个足球运动员的数据可视化图表

前言 用Python和Matplotlib绘制一个足球运动员的数据可视化图表。 Let’s start happily 开发工具 Python版本&#xff1a; 3.6.4 相关模块&#xff1a; bs4模块 requests模块 pandas模块 matplotlib模块 json模块 numpy模块 环境搭建 安装Python并添加到环境变量…

Sqoop数据导入 第2关:Mysql导入数据至HDFS上

为了完成本关任务,你需要掌握: 1、数据库( MySQL )建表。 2、Mysql 数据导入至 HDFS 中。 数据库( MySQL )建表 用命令进入 MySQL 客户端。 mysql -uroot -p123123 -h127.0.0.1 创建数据库hdfsdb(格式默认为utf8),并在数据库内建立表student,其表结构如下: mys…

通过求解数学模型来选择编码节点的最佳数量和位置(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

【✨十五天搞定电工基础】电阻电路的分析方法

本章要求1. 掌握支路电流法、叠加原理和戴维宁定理等电路的基本分析方法; 2. 了解实际电源的两种模型及其等效变换; 3. 了解非线性电阻元件的伏安特性及静态电阻、动态电阻的概念&#xff0c;以及简单非线性电阻电路 的图解分析法。 目录 一、电阻串并联连接的等效变换 1、…

企业如何有效的防爬虫?

防爬虫&#xff0c;简单来说&#xff0c;就是在尽量减少对正常用户的干扰的情况下尽可能的加大爬虫的成本。 而反防爬虫&#xff0c;或者说制造隐蔽性强的爬虫&#xff0c;就是尽量模拟正常用户的行为。 这两者是动态博弈的。大公司基本都有防爬的项目&#xff0c;以保护数据…

一图了解es6常用数据迭代函数map,filter,fill,reduce

一、一图胜千言 前端开发中&#xff0c;js数组处理是最常用的&#xff0c;除了for循环外&#xff0c;随着es6的普及&#xff0c;像reduce()、filter()、map()、some()、every()以及…展开属性都是最常用到的。 今天偶然从网上看到这张图&#xff0c;真是眼前一亮&#xff0c;真…

盘点JAVA中延时任务的几种实现方式

场景描述 ①需要实现一个定时发布系统通告的功能&#xff0c;如何实现&#xff1f; ②支付超时&#xff0c;订单自动取消&#xff0c;如何实现&#xff1f; 实现方式 一、挂起线程 推荐指数&#xff1a;★★☆ 优点&#xff1a; JDK原生(JUC包下)支持&#xff0c;无需引入新…

RabbitMQ之集群管理

1、在node2、node3、node4三台Linux虚拟机中安装RabbitMQ。 2、从node2拷贝.erlang.cookie到node3、node4的相应目录 如果没有该文件&#xff0c;手动创建/var/lib/rabbitmq/.erlang.cookie &#xff0c;生成Cookie字符串&#xff0c;或者启动一次RabbitMQ自动生成该文件。生产…

五年Java编程生涯,大专学历最终逆袭阿里,面试+学习+经历分享

五年时间&#xff0c;对于程序员来说&#xff0c;真的非常非常宝贵&#xff0c;掉的头发都够塞满键盘的缝隙了。就说新一代偶像 TFboys 吧&#xff0c;你应该知道这个组合吧&#xff0c;黄金合作期也就三五年的时间&#xff0c;现在基本上就处于各自单飞&#xff08;solo&#…

深度学习笔记之受限玻尔兹曼机(一)玻尔兹曼分布介绍

机器学习笔记之受限玻尔兹曼机——玻尔兹曼分布介绍引言回顾&#xff1a;Hammersley-Clifford定理玻尔兹曼分布的物理意义引言 从本节开始&#xff0c;将介绍受限玻尔兹曼机。本节将从马尔可夫随机场开始&#xff0c;介绍玻尔兹曼机分布。 回顾&#xff1a;Hammersley-Cliffo…

NCP81239MNTXG 开关降压/升压控制器,USB 功率传递和 Type-C 应用

NCP81239MNTXG USB 功率传递 (PD) 控制器是一款同步降压/升压控制器&#xff0c;适用于为笔记本电脑、平板电脑、台式系统以及很多使用 USB PD 标准和 C−Type 线缆的其他消费设备提供电池电压或适配器电压到所需电源轨的转换。结合使用 USB PD 或 C−Type 接口控制器时完全符合…

【笔记】Java - VM options、Program arguments、Environment variables、eclipse variables

java使用ide开发的时候&#xff0c;运行程序&#xff08;application&#xff09;前都要设置启动配置&#xff1a; VM options、Program arguments、Environment variables 很多时候我们是默认配置启动的&#xff0c;所以没太注意。但是如果我们有特殊需求、项目上线时&#xf…

VSCode 安装教程(超详细)

文章目录VSCode 安装使用教程&#xff08;图文版&#xff09;那么&#xff0c;什么是 IDE 呢 &#xff1f;目前&#xff0c;前端开发主流的 IDE 有以下 5 个下边我们开始玩转 VSCodeVSCode 下载、安装Window 版 VScode 安装流程1、下载 Vscode 安装文件2、下载完成单击运行&…

Postman的使用——设置全局参数,参数的传递,从登录接口的响应body中提取数据更新全局参数,从响应cookie中提取数据更新全局变量

Postman的使用——设置全局参数&#xff0c;引用全局参数&#xff0c;参数的传递&#xff0c;从登录接口的响应body中提取数据更新全局参数&#xff0c;从响应cookie中提取数据更新全局变量一、设置全局参数二、引用全局参数三、从登录接口的响应body中提取数据更新全局参数四、…

cmd命令以及一些操作

文章目录前言set和echoif语句判断有无指定文件夹相对路径创建文件夹创建bat脚本换行符前言 因为下载下来的代码用bash脚本写的&#xff0c;cmd不能完美运行&#xff0c;因此想着对照着转成cmd&#xff0c;这样就方便了。 set和echo set demohello world!!! echo %demo%这就是…