14 程序地址空间

news2024/11/25 0:38:58

背景

kernel 2.6.32
32位平台

空间布局图

在这里插入图片描述

如何理解地址划分
地址划分,本质是调整地址空间的定义start和end,内存中定义了管理每个区域范围的结构体,叫mm_struct,每个进程都有一个这个结构体指针变量
在这里插入图片描述

验证上面划分的结构,写一段各个属性变量的代码来验证地址

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

int g_unval;
int g_val = 100;


int main(int argc, char *argv[], char *env[])
{
   // int a = 10;
    //字面常量
   const char *str = "helloworld";
   // 10;
   // 'a';
  //main函数地址
    printf("code addr: %p\n", main);
    printf("init global addr: %p\n", &g_val);
    printf("uninit global addr: %p\n", &g_unval);

    static int test = 10;
    char *heap_mem = (char*)malloc(10);
    char *heap_mem1 = (char*)malloc(10);
    char *heap_mem2 = (char*)malloc(10);
    char *heap_mem3 = (char*)malloc(10);
    printf("heap addr: %p\n", heap_mem); //heap_mem(0), &heap_mem(1)
    printf("heap addr: %p\n", heap_mem1); //heap_mem(0), &heap_mem(1)
    printf("heap addr: %p\n", heap_mem2); //heap_mem(0), &heap_mem(1)
    printf("heap addr: %p\n", heap_mem3); //heap_mem(0), &heap_mem(1)

    printf("test stack addr: %p\n", &test); //heap_mem(0), &heap_mem(1)
    printf("stack addr: %p\n", &heap_mem); //heap_mem(0), &heap_mem(1)
    printf("stack addr: %p\n", &heap_mem1); //heap_mem(0), &heap_mem(1)
    printf("stack addr: %p\n", &heap_mem2); //heap_mem(0), &heap_mem(1)
    printf("stack addr: %p\n", &heap_mem3); //heap_mem(0), &heap_mem(1)

    printf("read only string addr: %p\n", str);
    for(int i = 0 ;i < argc; 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;
}

在这里插入图片描述

首先是代码地址,在最小的位置。最往上是字符常量区,然后是数据区,static也在数据区,本质是将局部的变量开辟在全局区域。堆区后面是栈区,中间空了很大一部分的共享区。两个箭头表示,堆的变量是往上增长,地址越来越大,栈则是越来越小,栈上面有命令行参数,在之后是环境变量的地址,最后是内核空间1G

在32位系统下,一个进程的地址空间,取值范围是0x00000000 - 0xffffffff
用户空间【0,3GB】 ,内核空间【3,4GB】

地址空间是操作系统专门为进程设计的内核数据结构,包含了各个区域的划分,起始和结束,还有更多属性
所以创建一个进程,操作系统先创建PCB结构,再创建地址空间,用地址空间指针指向进程的地址空间对象,就可以找到地址空间和对应的页表

每一个进程都有一份地址空间

虚拟内存

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
 pid_t id = fork();
 if(id < 0){
 perror("fork");
 return 0;
 }
 else if(id == 0){ //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
 g_val=100;
 printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }else{ //parent
 sleep(3);
 printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }
 sleep(1);
 return 0;
}
//与环境相关,观察现象即可
child[3046]: 100 : 0x80497e8
pa

上面的代码运行后,子进程修改了全局变量的值,结果同一个变量产生了两个不同的值,且他们的地址是一样的,这是为什么

  • 变量内容不一样,但地址一样,所以这个地址肯定不是真正的物理地址
    需要说明一下地址空间的设计
    由于直接访问物理内存是不安全的,如果进程都直接访问物理内存,那么很容易一个进程用指针修改另一个进程的值,不遵守进程的独立性。所以,引入了虚拟内存的概念,进程直接访问虚拟内存,虚拟内存就是上面的0x0-0xffffffff的内存布局,每个进程都划分了这么大的空间,实际上每个进程这些空间只是物理内存的一部分

在这里插入图片描述

那么一个虚拟内存地址如何转化为对应的物理内存地址,物理内存和虚拟内存中间有一个页表的结构,里面记录了地址的对应关系。地址空间和页表(用户级)每个进程都有一份,只要保证,每一个进程的页表,映射的物理内存的不同区域,这样进程之间就不会互相干扰,保证了独立性

分页和虚拟地址空间

在这里插入图片描述

这时就可以解释上面为什么同一个变量会有两个不同的值,fork产生子进程后,子进程的变量分页结构等很多都是基于父进程的拷贝,共享一段内存。当父子进程对某个值写入时,会为子进程单独拷贝这个变量的一个区域,映射和父进程不同的物理内存位置。所以虽然都是同一个变量的虚拟内存地址,但在物理内存处是两块不同的区域,这个过程就叫写时拷贝

fork为什么会有两个返回值
前面说过是因为return执行了两次,return的本质就是对id变量进行写入,发生了写时拷贝,父子进程在物理内存中都有属于自己的地址空间,只不过用同一个虚拟地址来标识了

虚拟内存的产生

在没有虚拟内存的时候,进程是直接加载到物理内存上,通过进程的起始和边界控制是不是自己的部分。这样可以通过指针访问到另一个进程的数据,如果一个进程有问题,越界也可能会导致另一个程序崩溃

所以引入了虚拟内存的概念,虚拟内存通过页表映射到物理内存中,虚拟内存作为中间者,如果转换后是非法的,要么转换后是非法的,要么越界,要么没有权限,就会禁止访问,解决了安全性的问题

当我们程序还没有运行,编译形成可执行程序的时候,就已经有了地址。地址空间不仅仅是OS内部遵守的,编译器也要遵守。即编译器编代码的时候就已经形成了各个代码区,数据区,并且,采用和linux内核中一样的编址方式,给每一个变量代码都编址,所以,程序编译的时候,每一个字段早已经有了一个虚拟地址,每一个变量,每一个函数,编译器给的都有地址
,同样也一定被加载到了物理内存

有两套地址,一套是程序内部使用的,一套是加载到内存分页的物理内存地址。用代码和函数的地址作为页表的左值,得到对应的物理地址右值

cpu读到的是物理地址还是虚拟地址?
在这里插入图片描述
cpu读到的也是虚拟地址,通过页表转换为物理地址操作

为什么要有地址空间

1.凡是非法的访问或者映射,操作系统都会识别到,并终止这个进程。这样,有效的保护了物理内存,地址空间和页表是OS创建的,凡是使用地址空间和页表进行映射,都在OS的监管之下,保护了所有的合法数据和进程有效数据

所有的进程崩溃,就是进程退出,系统杀掉了这个进程

2.因为有地址空间的存在,页表映射的存在,代码和数据就可以加载到任意位置。内存管理和进程管理完成了解耦合

new和malloc空间的时候,本质是在虚拟内存申请的,使用了延迟分配的策略,提高效率。
如果申请了物理空间如果不立马使用,造成了空间浪费。所以,申请一段空间的时候,物理内存可以一个字节都不给,只有在真正对这个空间访问的时候,才执行相关内存的管理算法,申请内存,构建映射关系,内存的访问由操作系统自动完成,用户和进程0感知。操作系统如何知道虚拟内存分配的空间需要被访问而未被加载物理内存,用了缺页中断技术。这样就不会存在申请了但不用的空间

3.物理内存理论上可以任意位置加载,会造成数据和代码乱序。但是,因为有页表的存在,可以将内存分布有序化。进程的代码和数据如果已经运行完了可以去除,映射关系也删掉,但不影响后面的代码运行。不同的进程映射到不同的物理内存,很容易做到,独立性的实现

因为有地址空间的存在,每一个进程都认为自己拥有4GB空间(32),并且各个区域有序的,进而可以通过页表映射到不同的区域,来实现进程的独立性。每个进程不需要知道其他进程的存在

重新理解挂起

加载程序是创建进程,并不需要立马把所有程序的代码和数据加载到内存中,创建映射关系。极端情况下,只有内核数据结构被加载到内存中,当真正执行这段代码和数据的时候,才创建物理内存,这样就可以实现分批加载和分批换出。比如100G的游戏怎么运行,只加载需要运行的进程,分批换出。

挂起的时候,页表不仅仅只能映射物理内存,还可以映射磁盘,只需要填入映射到磁盘中代码数据的位置,将物理内存中的位置释放。就可以把程序挂起,不用交换到磁盘上

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

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

相关文章

QCustomPlot 一个X轴多个Y轴

文章目录 大致效果如下&#xff1a; 相关代码如下&#xff1a; centerWidgetLayout->addLayout(hboxLayout,1);customplot new QCustomPlot(centerWidget);centerWidgetLayout->addWidget(customplot,100);int xPointNum 1300 ;customplot->plotLayout()->clear…

鸿蒙Harmony应用开发—ArkTS声明式开发(手势处理:绑定手势方法)

为组件绑定不同类型的手势事件&#xff0c;并设置事件的响应方法。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 绑定手势识别 通过如下属性给组件绑定手势识别&#xff0c;手势识别成功后可以通过事…

Docker容器数据卷使用

创建容器 将本地的/home/ceshi和容器的/home目录进行一个挂载,文件内容会进行同步 -v参数就是进行一个卷的挂载 主机路径:容器内的路径 [rootwq ~]# cd /home/ [rootwq home]# ll total 8 drwx------ 3 admin admin 4096 Dec 29 10:16 admin drwx------ 2 www www 4096…

如何使用DS file+cpolar内网穿透实现远程访问本地群晖NAS传输文件

文章目录 1. 群晖安装Cpolar2. 创建TCP公网地址3. 远程访问群晖文件4. 固定TCP公网地址5. 固定TCP地址连接 DS file 是一个由群晖公司开发的文件管理应用程序&#xff0c;主要用于浏览、访问和管理存储在群晖NAS&#xff08;网络附加存储&#xff09;中的文件。这个应用程序具有…

【C++】类和对象(中)一篇文章带你学会六大默认成员函数

目录 一、类的6个默认成员函数二、 构造函数2.1 概念2.2 特征 三、析构函数3.1 概念3.2 特性 四、拷贝构造函数4.1 概念4.2 特征 五、赋值运算符重载5.1 运算符重载5.2 赋值运算符重载5.3 前置和后置重载 六、日期类的实现七、const成员八、取地址及const取地址操作符重载结尾 …

新品发布会媒体邀请,邀约记者现场报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 新品发布会媒体邀请及记者现场报道邀约流程&#xff1a; 一、策划准备 明确新品发布会时间、地点和主题。 制定媒体邀请计划&#xff0c;确定目标媒体。 二、邀请媒体 向目标媒体发送…

关于制作Python游戏全过程(汇总1)

目录 前言: 1.plane_sprites模块: 1.1导入模块: 1.1.1pygame&#xff1a;一个用于创建游戏的Python库。 1.1.2random&#xff1a;Python标准库中的一个模块&#xff0c;用于生成随机数。 1.2定义事件代号: 1.2.1ENEMY_EVENT&#xff1a;自定义的敌机出场事件代号&#xf…

TypeScript 哈希表

文章目录 概念哈希化冲突链地址法开放地址法 装填因子&#xff08;loadFactor&#xff09;效率对比哈希函数字符串转数字算法 —— 幂的连乘压缩数字范围 —— 取余优秀哈希算法的优点快速计算&#xff1a;霍纳法则均匀分布 —— 质数Java 中的 HashMapN次幂的底数 实现哈希函数…

基于QGIS的研究区域遥感影像裁切下载方法-以岳麓区为例

目录 前言 一、数据说明 1、遥感影像 2、矢量范围 二、按矢量范围导出 1、第一步、导出影像 2、第二步、设置输出格式 3、设置裁切范围 4、设置分辨率 三、按矢量范围掩膜 1、第一步、打开裁剪工具 2、第二步、参数设置 ​编辑 3、执行掩膜 四、webgis支持 1、生成运行…

NineData云原生智能数据管理平台新功能发布|2024年2月版

SQL开发&#xff1a;全功能支持百度云 GaiaDB 介绍&#xff1a;支持通过 SQL 开发所有能力管理 GaiaDB 实例。更多信息&#xff0c;请参见&#xff1a;真香&#xff01;NineData SQL 开发全面适配 GaiaDB 场景&#xff1a;企业使用 GaiaDB 管理企业数据&#xff0c;需要一个一…

【EI会议征稿通知】第三届信息经济、数据建模与云计算国际学术会议 (ICIDC 2024)

第三届信息经济、数据建模与云计算国际学术会议 2024 3rd International Conference on Information Economy, Data Modeling and Cloud Computing&#xff08;ICIDC 2024&#xff09; 第三届信息经济、数据建模与云计算国际学术会议(ICIDC 2024)定于2024年6月21-23日在中国…

javaWebssh药品进销存信息管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh药品进销存信息管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOM…

YOLOv8-Openvino-ByteTrack【CPU】

纯检测如下&#xff1a; YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 注&#xff1a;YOLOv8和YOLOv9代码内容基本一致&#xff01; 全部代码Github&…

[数据集][图像分类]芒果叶病害分类数据集4000张5类别

数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;4000 分类类别数&#xff1a;8 类别名称:["anthracnose","bacterial_canker","cutting_weevil","die_back",&…

EasyRecovery易恢复14最新版Win电脑安装包下载

EasyRecovery易恢复是一款数据恢复软件。它专门用于恢复因各种情况&#xff08;如误删除、格式化、病毒攻击、分区丢失等&#xff09;而丢失的数据。这款软件支持恢复多种类型的文件&#xff0c;包括文档、图片、视频、音频等&#xff0c;并且可以从各种存储设备&#xff08;如…

【YOLO v5 v7 v8 v9小目标改进】HTA:自注意力 + 通道注意力 + 重叠交叉注意力,提高细节识别、颜色表达、边缘清晰度

HTA&#xff1a;自注意力 通道注意力 重叠交叉注意力&#xff0c;提高细节识别、颜色表达、边缘清晰度 提出背景框架浅层特征提取深层特征提取图像重建混合注意力块&#xff08;HAB&#xff09;重叠交叉注意力块&#xff08;OCAB&#xff09;同任务预训练效果 小目标涨点YOLO…

06 - 镜像管理

1 了解镜像 Docker镜像是一个特殊的文件系统&#xff0c;除了提供容器运行时所需的程序、库、资源、配置等文件外&#xff0c;还包含了一些为运行时准备的一些配置参数&#xff08;如匿名卷、环境变量、用户等&#xff09;。 但注意&#xff0c; 镜像不包含任何动态数据&#…

sql多表运用 12.3

肖SIR__数据库之多表运用__12.3 数据库之多表运用 CREATE table dept(dept1 VARCHAR(6),dept_name VARCHAR(20)) default charsetutf8; INSERT into dept VALUES (101,财务); INSERT into dept VALUES (102,销售); INSERT into dept VALUES (103,IT技术); INSERT into dep…

【已解决】conda环境下ROS2 colcon build编译选择特定python解释器

目录 1 问题背景2 问题探索3 问题解决4 告别Bug 1 问题背景 环境&#xff1a; ROS2 HumbleUbuntu22.04 现象&#xff1a;运行colcon build后由cpp编译生成的python导出库(如自定义消息、服务等)&#xff0c;其版本与由python setup.py安装的python库版本不一致&#xff0c;导致…

App自动化测试笔记(四):UIAutomatorViewer与元素定位API

UIAutomatorViewer 1、应用场景 定位元素的时候必须根据元素的相关特征来进行定位&#xff0c;而 UIAutomatorViewer 就是用来获取元素特征的。 如何使用UIAutomatorViewer 1、保证想要查看的元素在当前的频幕上 2、打开UIAutomatorViewer工具 3、点击左上角左数第二个按钮…