【Linux进程篇】Linux内核——程序地址空间的初构

W...Y的主页 😊

代码仓库分享💕 


程序地址空间回顾

我们在讲C语言的时候,大家应该都见过这样的空间布局图:

为了更好的验证不同的数据在内存中的存储位置,下面这段代码我们可以去实验一下:

#include<stdio.h>
#include<stdlib.h>
int g_val = 100;
int g_unval;
int main(int argc, char *argv[], char *env[])
{
    printf("code addr: %p\n", main);
    printf("init data addr: %p\n", &g_val);
    printf("uninit data addr: %p\n", &g_unval);

    char *heap = (char*)malloc(20);
    char *heap1 = (char*)malloc(20);
    char *heap2 = (char*)malloc(20);
    char *heap3 = (char*)malloc(20);
    static int c;
    printf("heap addr: %p\n", heap);
    printf("heap1 addr: %p\n", heap1);
    printf("heap2 addr: %p\n", heap2);
    printf("heap3 addr: %p\n", heap3);

    printf("stack addr: %p\n", &heap);
    printf("stack addr: %p\n", &heap1);
    printf("stack addr: %p\n", &heap2);
    printf("stack addr: %p\n", &heap3);
    printf("c addr: %p, c: %d\n", &c, c);

    for(int i = 0; argv[i]; i++)
    {
        printf("&argv[%d]=%p\n", i, &argv[i]); 
    }
    for(int i = 0; env[i]; i++)
    {
        printf("&env[%d]=%p\n", i, &env[i]);
    }

    return 0;
}

 

这就是我们所打印出来的结果,我们可以知道:

1.堆与栈是相对而生的。

2.先有命令行操作符地址再有环境变量的地址 

如果我们想看一下命令行与环境变量存的字符串所在的地址,我们需要稍微修改一下代码:

for(int i = 0; argv[i]; i++)
{
    printf("argv[%d]=%p\n", i, argv[i]); 
}
for(int i = 0; env[i]; i++)
{
    printf("env[%d]=%p\n", i, env[i]);
}

 

 这样我们就能看出无论是表还是表指向的项目,都是在栈空间的上面保存着!!!

而我们的static变量的存储位置在未初始变量与初始化数据直接,说明操作系统已经默认把static变量默认成全局变量了,所以他会在我们进程运行期间一直存在不会被销毁。 

那上面的结构图中的地址,是内存的地址吗?我们再来看一段代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int g_val = 100;
int g_unval;
int main()
{
    pid_t id = fork();
    if (id == 0)
    {
        int cnt = 0;
        //子进程
        while (1)
        {
            printf("child, pid: %d, ppid: %d, g_val: %d, &g_val: %p\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
            cnt++;
            if (cnt == 5)
            {
                g_val = 200;
                printf("child change g_val: 100->200\n");
            }
        }
    }
    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 等于100,当我们让程序运行5秒后在子进程中修改g_val的内容,将100改到200后,我们在进行观察发现子进程中的g_val被修改成200,而父进程的g_val不变。但是父子进程中的g_val的地址却是相同的!!! 

内容不一样地址却一样???综上所述:这个地址绝对不是内存物理地址!!!

这个地址被叫做虚拟地址或者线性地址。 所以我们所使用的地址全都不是物理地址。我们所打印的地址看到的空间排布不是物理内存。

进程地址空间

地址空间(address space)表示任何一个计算机实体所占用的内存大小。比如外设、文件、服务器或者一个网络计算机。地址空间包括物理空间以及虚拟空间。

物理地址 (physical address): 放在寻址总线上的地址。放在寻址总线上,如果是读,电路根据这个地址每位的值就将相应地址的物理内存中的数据放到数据总线中传输。如果是写,电路根据这个地址每位的值就将相应地址的物理内存中放入数据总线上的内容。物理内存是以字节(8位)为单位编址的。

虚拟地址 (virtual address): CPU启动保护模式后,程序运行在虚拟地址空间中。注意,并不是所有的“程序”都是运行在虚拟地址中。CPU在启动的时候是运行在实模式的,内核在初始化页表之前并不使用虚拟地址,而是直接使用物理地址的。

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

这就说明在我们的g_val中子进程先将我们父进程的地址空间进行拷贝,而我们的页表如同我们的hash映射一样,将我们的虚拟地址与物理地址进行映射,所以父子进程的g_val的虚拟地址是相同的。

当我们对子进程的值进行修改时,我们操作系统会在物理内存中开辟另一块空间进行储存,而我们的页表的映射关系也会发生改变。即key的值不会改变但value的值会发生改变。

进程地址空间在每一个进程中都会存在一个进程地址空间,在32位操作系统下的范围是[0,4GB]。

在操作系统下管理地址空间就如同管理硬件或PCB,都是创建一个结构体进行管理的其对应的都是数据结构。

那管理进程空间的结构体里面都有说明数据呢?PCB结构体指令中肯定有一个指针指向管理进程空间的结构体中:

 

上图我只截取了一小部分源码,从中我们可以看出有许多划分空间的指针,这些都是为了划分物理内存的虚拟内存指针,还有记录代码、数据、堆、栈等等开始结束的位置。而区域划分的本质就是区域内的各个地址都可以使用 。

我们的地址空间不具备对我们的代码和数据的保存能力,他们都存在物理空间。而给我们一张进程映射表——页表可以将地址空间转换到物理空间中去。

为什么要有地址空间呢?

1.将物理内存从无序变有序,让进程以统一的视角进行管理

2.将进程管理和内存管理进行解耦合

3.内存地址空间+页表是保证内存安全的重要收段

 malloc/new是如何申请空间的呢?

首先我们就要理解new/malloc的堆空间申请开辟后我们不一定是直接使用的。可能是过去1ms甚至1s后我们才去使用的。但是操作系统的主旨是一定要为效率和资源使用率负责的!!!所以我们经常使用的new/malloc本质先不会直接在物理内存中申请开辟空间,而是在虚拟地址中先进行开辟。但是页表中却没有对应物理地址的映射,只有当我们准备进行写入时才会有对应的物理地址和映射关系的出现!!!

这样做的好处是:

1.充分保证内存的使用率。

2.提升new和malloc的性能


以上就是本次的内容,我们已经学习了进程的基本概念,下篇博客我们将学习如何操作进程,请尽情期待!!! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

通过ESP32芯片模组实现产品智能化升级,启明云端乐鑫代理商

随着科技的不断进步&#xff0c;物联网&#xff08;IoT&#xff09;已经渗透到我们生活的方方面面&#xff0c;成为现代生活不可或缺的一部分。在这场智能化革命中&#xff0c;乐鑫科技以其创新的ESP32芯片模组&#xff0c;为智能家居和智能设备的发展注入了新的活力。作为乐鑫…

【Flutter】交错动画自定义动画Hero动画

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Flutter学习 &#x1f320; 首发时间&#xff1a;2024年5月29日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e; 目…

虚拟化概述

虚拟存储器(Virtual Memory) 它的基本思想是对于一个程序来说,它的程序(code)、数据(data)和堆栈(stack)的总大小可以超过实际物理内存的大小&#xff1b;操作系统把当前使用的部分内容放到物理内存中&#xff0c;而把其他未使用的内容放到更下一级存储器&#xff0c;如硬盘&a…

Windows电脑高颜值桌面便利贴,便签怎么设置

在这个看颜值的时代&#xff0c;我们不仅在衣着打扮上追求时尚与美观&#xff0c;就连电脑桌面也不愿放过。一张唯美的壁纸&#xff0c;几款别致的小工具&#xff0c;总能让我们的工作空间焕发出不一样的光彩。如果你也热衷于打造高颜值的电脑桌面&#xff0c;那么&#xff0c;…

积鼎CFDPro水文水动力模型,专为中小流域洪水“四预”研发的流体仿真技术

水动力模型与水文模型是水利工程与水文学研究中不可或缺的两大工具。水动力模型着重于流体运动的动力学机制&#xff0c;通过一系列方程组捕捉水流的时空变化&#xff0c;而概念性水文模型则侧重于流域尺度的水文循环过程&#xff0c;利用物理概念与经验关系进行近似模拟。两者…

OpenBuild推出Sui Quiz任务,瓜分500SUI奖励

Quiz 功能 让用户可以&#xff1a; - 测试对某个知识点的理解力&#xff1b; 通过测试后获得 NFT 凭证&#xff0c;未来该凭证可用于求职认可、Bounty 任务、空投门槛。 Sui 是一个高性能的去中心化平台&#xff0c;旨在解决传统区块链系统中的可扩展性和效率问题。其独特的架…

win_os_linux不能用于文件名的保留字符

windows 在 Windows 文件系统中&#xff0c;以下字符是保留字符&#xff0c;不能用于文件名或目录名&#xff1a; < (小于号)> (大于号): (冒号)" (双引号)/ (斜杠)\ (反斜杠)| (竖线)? (问号)* (星号) 此外&#xff0c;文件名不能以空格或句点 (.) 结尾&#x…

win10如何查看本机ip地址?三招搞定,快来试试吧

在数字化时代&#xff0c;IP地址作为网络设备的唯一标识&#xff0c;对于计算机使用者来说具有重要意义。无论是为了进行网络设置、远程连接&#xff0c;还是解决网络问题&#xff0c;了解如何查看本机IP地址都是一项必备技能。对于使用Windows 10操作系统的用户来说&#xff0…

word 替换全部字母和数字为新罗马

步骤1&#xff0c;准备好一份测试文档 Adfafdafdafdafdsafdsafasdfdsa 汇总的时光发生的尬的算法的萨法asdfasfsafda大法师短发沙发上对方阿福的萨法的算法大法大方发达舒服打发到沙发上对方说 打发打发打发的负担啊大方阿道夫大法东方大厦发大水Ameti 1. Adafe我直打大噶特区…

2024-05-29 服务器开发-c++线程池与task-思考

摘要: 无论是什么系统&#xff0c;线程池和task都是给上层所提供的基础的功能单元。本文记录一些核心的设计思想。 线程池要面对的场景: 调用下层接口时&#xff0c;被IO阻塞&#xff0c;导致整个服务无法对外提供服务更上层调用本模块接口时&#xff0c;是需要做到同步&#…

WebGL实现医学教学软件

使用WebGL实现医学教学软件是一个复杂但非常有益的项目&#xff0c;可以显著提升医学教育的互动性和效果。以下是详细的实现步骤&#xff0c;包括需求分析、技术选型、开发流程和注意事项。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作…

[NLP]如何训练自己的大型语言模型

简介 大型语言模型&#xff0c;如OpenAI的GPT-4或Google的PaLM&#xff0c;已经席卷了人工智能领域。然而&#xff0c;大多数公司目前没有能力训练这些模型&#xff0c;并且完全依赖于只有少数几家大型科技公司提供技术支持。 在Replit&#xff0c;我们投入了大量资源来建立从…

2024长三角快递物流展即将亮相,致鸿物流器材有限公司值得关注

广东致鸿物流器材有限公司&#xff0c;前身为广州致鸿物流器材有限公司&#xff0c;成立于2002年初&#xff0c;是一家中国专业仓储笼研发制造公司&#xff0c;公司员工约400名&#xff0c;日产仓储笼制造规模近8000个&#xff0c;在全国范围内有五大配送服务中心&#xff1a;江…

降雨量应急监测站的工作原理

TH-YJ3】雨量监测站是一种自动化的气象监测设备&#xff0c;主要用于实时、准确地监测和记录降雨量数据。它通过安装在特定位置的传感器和数据处理设备&#xff0c;连续监测降雨的强度、持续时间和降雨分布等信息&#xff0c;为气象、水文、环境等领域的研究和应用提供数据支持…

Java常见集合类一(List)

一、Collection接口及其常见实现子类、子接口 由上图可以看出&#xff0c;Collection 接口实现了 Iterable 接口&#xff1b; Iterable接口是Java集合类中的核心接口之一&#xff0c;实现该接口的类具有迭代功能&#xff0c;它提供了能够对实现它的子类 中的元素进行逐个遍历的…

端午节趣味互动小游戏的作用是什么

端午节吃粽子&#xff0c;多数行业商家都可借势进行品牌营销&#xff0c;而一场营销效果的优劣&#xff0c;除了好方案外&#xff0c;还需要好的工具/渠道及运营等&#xff0c;围绕粽子元素的互动小游戏是营销互动的主要形式之一。 运用【雨科】平台拥有多款端午节粽子主题互动…

【C语言】atoi函数的使用及模拟实现

atoi (ascii to integer)&#xff0c;是把参数 str 所指向的字符串转换为一个整数&#xff08;int类型&#xff09;的库函数。 使用场景 引子&#xff1a; 有兴趣的朋友可以听我逐句翻译一下cpluscplus.com里的这段解释&#xff08;要考六级了练一下&#xff09;&#xff1a; …

嵌入式进阶——EEPROM读写

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 设置EEPROM读写String字符串官方示例 EEPROM是一种可擦写可编程只读存储器&#xff08;Electrically Erasable Programmable Read-…

MT2076 小码哥处理订单

思路&#xff1a; 使用二分&#xff1a;题目中隐含条件&#xff1a;如果不满足&#xff0c;需要找到第一个不满足的订单。 二分法需要满足单调性or有一个界线使前后两部分性质相反。这里的”界线“为&#xff1a;是否满足条件。假设第i天无法满足&#xff0c;则后面的所有天都…

SAP ABAP MD04屏幕增加:增加列

需求:增加显示销售订单送达方 主要使用二代增强出口:M61X0002 事务码T-code:CMOD 填写描述,保存到对应的包下 分配增强到项目下 激活组件,激活后效果如下 编写ZXM61U04 SAP留出的按钮,填写描述 button1_ez = 送达方. 编写ZXM61U03 *&-------------------------…