Linux:程序地址空间/虚拟地址等相关概念理解

news2024/10/6 8:40:23

文章目录

  • 程序地址空间
  • 虚拟地址和物理地址
    • 地址的转换
    • 地址空间是什么?

程序地址空间

CC++程序中,一直有一个观点是,程序中的各个变量等都会有一定的地址空间,因此才会有诸如取地址,通过地址访问等操作,那么在前面的学习中,基本有下面的概念

在这里插入图片描述

这是学C语言的时候就已经知晓的内容,那么现在抛出下面的几个疑问:这些数据和所谓的地址是内存中的地址吗?内存中的地址存储排列形式如此整齐吗?不会造成内存浪费吗?

下面做一个小实验:

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



int g_val = 100;
int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
        int cnt = 5;
        while(1)
        {
            printf("child, Pid: %d, Ppid: %d, g_val: %d, &g_val=%p\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
            if(cnt == 0)
            {
                g_val=200;
                printf("child change g_val: 100->200\n");
            }
            cnt--;
        }
    }
    else
    {
        //father
        while(1)
        {
            printf("father, Pid: %d, Ppid: %d, g_val: %d, &g_val=%p\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
        }
    }

    sleep(100);
    return 0;
}

实验结果如下:

child, Pid: 6781, Ppid: 6780, g_val: 100, &g_val=0x60105c
father, Pid: 6780, Ppid: 30413, g_val: 100, &g_val=0x60105c
child change g_val: 100->200
child, Pid: 6781, Ppid: 6780, g_val: 200, &g_val=0x60105c
father, Pid: 6780, Ppid: 30413, g_val: 100, &g_val=0x60105c

这是一个很神奇的现象,父进程和子进程的g_val选项的地址是一样的,但是读取出来的值却不一样,这是为什么呢?

说明这里的地址,并不是物理地址,而是虚拟地址,也叫做线性地址

虚拟地址和物理地址

下面就来研究的是,虚拟地址和物理地址之间是如何进行转换的

地址的转换

由前面的内容知道,进程是由进程的代码和数据以及内核数据结构组成的,那么当一个进程生成的时候会创建其对应的PCB用来管理进程中的数据,而在进程中的数据会根据具体的类型而放入不同的地址空间中,例如栈区,堆区,代码区等等…

而实际上,这个区域只是一个虚拟的地址,由于一些原因(后续补充),存在一个叫做页表的映射关系,将虚拟地址和物理地址进行一一映射,具体的表现如下所示:

在这里插入图片描述
上图即展示了页表的映射关系的具体含义,对于前面图片中的内容只是一个虚拟地址,打印出来的信息也并非实际的物理地址,而真正的物理地址则是通过页表进行一个一一映射的关系,通过这个一一映射就能够找到物理地址,这个物理地址才是真正存储信息的地方

那对于子进程来说是如何解释的?

由前面的理论基础可以得出这样的一个结论,当使用fork创建子进程的时候,为子进程创建自己的PCB,对于代码和数据,如果发生了变化就使用写时拷贝完成一份拷贝,这样可以保证进程的互不干扰独立性,因此对于上面的场景,当对于创建子进程的时候,本质上就是直接复制了一份上面图片中的内容,并将这个task_struct变成子进程:

下图中所示的页表是一部分,实际上的页表还有其他的组成部分

在这里插入图片描述
而当子进程或者父进程要发生数据改变的时候,就会发生写时拷贝,具体的产生过程如下:

在这里插入图片描述

这样,就解释清楚了写时拷贝的含义,写时拷贝是发生在物理内存中的拷贝过程,整个过程是由操作系统来完成的,保证了进程之间的独立性

地址空间是什么?

简单来说,地址空间就是它:

在这里插入图片描述
每一个进程都会有一个这样的地址空间,而对于地址空间是需要进行管理的,那么如何对地址空间进行管理?答案是先描述再组织,因此,如何对地址空间进行描述?

地址空间最终一定是一个内核的数据结构对象,简单来说就是一个内核的结构体,正如task_struct一样,在Linux内核中有一个名字,叫做mm_struct,而这个数据是如何进行管理的?答案很明显,也是在内核数据结构中进行的管理

Linux内核源码中,来查看这个结构体的存在性

在这里插入图片描述

转到关于它的定义,观看它内部的定义实现方式:

在这里插入图片描述
对于mm_struct来说,它通过定义了各个区域的起止位置来进行管理数据

为什么要有地址空间呢?

先说结论:

  1. 让进程以统一的视角看待内存,任意一个进程,都可以通过地址空间和页表,将杂乱无序的内存数据变成有序的空间,也就是说这是一个变无序为有序的过程
  2. 存在虚拟地址空间,可以有效的进行进程访问内存的安全检查
  3. 将进程管理和内存管理进行耦合
  4. 通过页表,可以让进程映射到不同的物理内存中,从而实现进程的独立性

下面对于上面的结论进行一一的解释:

1. 变无序为有序的过程

这个过程是很好理解的,由于页表的存在,因此具体的实际内存中的数据不必排放到一块,而是可以进行不同位置的存储,但是在管理的角度来看,通过虚拟地址来进行管理是相当方便的,每一个地方都被分门别类的具体一一列举了出来,这样不仅便于管理,同时也可以最大化的利用内存中的空间

2. 访问内存的安全检查

讲到这点,就必须对页表进行进一步的补充说明了,实际上页表中存储的不仅仅有虚拟地址和物理地址,还有其他很多的信息,例如这里的访问权限字段

在这里插入图片描述
那么首先是解释访问权限字段存在的意义:可以有效避免进行修改,保护进程的数据等功能,例如下面的这个具体事例

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

int main()
{
	char* str = "hello linux";
	*str = 'H';
	return 0;
}

gcc的编译器下,这是可以通过编译的,原因是这里的一个常量字符串的起始地址交给了一个字符指针str,而对于str来说将它的指向内容改成H,这个本身是可以的,但是问题出现在,str指向的内容实际上是一个字符常量区,而这个区域内的数据是不可以被修改的,因此如果要进行修改的话是不被允许的,那么页表是如何进行保护的呢?

在执行程序的时候会引发段错误,这就是页表的功劳,当使用虚拟地址进行映射到物理地址的过程中,在进行页表的权限访问字段的时候会发现这个字段的访问权限是只读权限,但是现在要进行写入,很明显这是不被允许的行为,因此就会终止这种行为,因此页表中的权限访问字段就有这样的功能,可以进行访问内存的安全检查

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

在解释这个结论前,还需要补充一下页表的内容,页表中还存在一列,它的意义是查看是否被分配和是否有内容

在这里插入图片描述
在实际中是采用一个01来表示是否有没有被分配和内容的,在实际进程管理控制过程中,虚拟地址首先会放到页表中,而当需要和内存地址进行交互的时候,就会通过这个分配和内容的内容表来进行判断,到底内存有没有分配具体的物理地址给这部分内容,如果没有就会进行分配等信息,也是方便于进程的管理

这样做,就把进程管理和内存管理这两个模块的耦合度大大降低,两个模块控制系统互不干扰,这样就实现了进程的独立性

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

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

相关文章

【软件设计师-中级——刷题记录7(纯干货)】

目录 每日一言&#xff1a;持续更新中...你的编程水平是&#xff1f; A 入门&#xff1a;我对编程没有一点儿经验 B. 初级&#xff1a;了解一点基础知识&#xff0c;但没有写过代码 C. 中级&#xff1a;会写点简单代码&#xff0c;能看懂代码 D. 高级&#xff1a;写过多段代码&…

基于springboot实现学生综合成绩测评系统项目【项目源码】计算机毕业设计

基于springboot实现学生综合成绩测评系统演示 开发技术与环境配置 以Java语言为开发工具&#xff0c;利用了当前先进的springboot框架&#xff0c;以MyEclipse10为系统开发工具&#xff0c;MySQL为后台数据库&#xff0c;开发的一个学生综合测评系统。 2.1 SpringBoot框架 S…

jsp内的${}循环一次及循环几次相加出总和

目录 表内读数据循环一次的相加显示&#xff1a; 表内读数据循环几次的相加&#xff0c;计算出总和并显示&#xff1a; 表内读数据循环一次的相加显示&#xff1a; <c:forEach items"${sessionScope.PropertyFeelist}" var"pf"><h5> ${pf.w…

Linux进程终止

进程终止 一.返回码&#xff08;错误码&#xff09;1.strerror2.errno 二.exit三._exit1.简单使用2.exit和_exit的区别 一.返回码&#xff08;错误码&#xff09; 其实进程终止不外乎就以下三种情况&#xff1a; 1.strerror 我们一般关心程序为什么会失败而不关心为什么会成功…

[管理与领导-122]:IT人看清职场中的隐性规则 - 18- 一半佛一半魔,一半君子一半小人,阴阳互转,生生不息,儒、释、道、法,一个不能少

目录 一、太极阴阳图&#xff1a;阴阳互转&#xff0c;生生不息 1.1 阴阳互转&#xff0c;生生不息 1.3 职场中儒、释、道、法 二、职场中的阴阳&#xff1a;君子与小人&#xff0c;善与恶 2.1 职场中的阴阳&#xff1a;君子与小人 2.2 职场中的阴阳&#xff1a;谁不是一…

LRC2024:Lightroom Classic 2024 (WinMac)

Lightroom Classic是一款由Adobe公司开发的数字图像处理和管理工具。它以强大的照片调整、处理、管理和分享功能而著称&#xff0c;被认为是专业摄影师的必备利器。 主要特性如下&#xff1a; 增强的校正工具&#xff1a;Lightroom Classic提供了丰富的照片校正工具&#xff0…

交换机端口灯常亮 端口up状态 服务器设置ip交换机获取不到服务器网卡mac地址 不能通信

环境: 深信服防火墙 8.0.75 AF-2000-FH2130B-SC S6520X-24ST-SI交换机 version 7.1.070, Release 6530P02 问题描述: 交换机一个vlan下有3台服务器,连接端口2、3、4,2和3连接的服务器正常,交换机3端口灯常亮 端口up状态 服务器自动获取不了地址,改为手动设置ip后,交…

冷笑话-1

代码检视时&#xff0c;程序员A看着下面的代码&#xff0c;疑惑地问程序员B&#xff1a;“为什么不用重载&#xff1f;” class MyClass {public MyClass queryById(long id) { //......}public MyClass queryByName(String Name) { //......}public MyClass queryByIdAndNam…

2023CANN训练营第二季——Ascend C算子开发(入门)——基础概念

第一章 Ascend C 算子开发入门 一、基础概念 1.Ascend C 概念&#xff1a;Ascend C是CANN针对算子开发场景推出的编程语言&#xff0c;原生支持C和C标准规范&#xff0c;最大化匹配用户开发习惯;通过多层接口抽象、自动并行计算、孪生调试等关键技术&#xff0c;极大提高算子…

Java并发编程常见面试题总结

梳理Java并发编程相关的面试题&#xff0c;主要参考《JAVA并发编程实战》(Brian Goetz, Joshua Bloch, David Holmes, Tim Peierls, Joseph Bowbeer, Doug Lea 著, 韩锴, 方妙 译)一书&#xff0c;其余部分整合网络相关内容。注意&#xff0c;关于Java基础相关的面试题可以参考…

‘conda‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

原因&#xff1a;环境变量没有正确添加解决&#xff1a;我的电脑—右键属性—高级系统设置—环境变量—系统变量—Path—双击进入—新建&#xff0c;去安装Anaconda的目录下&#xff0c;找到Library中的bin&#xff0c;将此时的路径粘贴到此处

Python学习第3天-第一个Python程序

文章目录 前言一、创建项目二、创建程序总结 前言 下面给大家展示下经典的Hello World! 一、创建项目 二、创建程序 print("Hello World!")总结 回到顶部 学习网站 欢迎来到Python的世界&#xff01;

Leetcode1833. 雪糕的最大数量

Every day a Leetcode 题目来源&#xff1a;1833. 雪糕的最大数量 解法1&#xff1a;贪心 排序 本题唯一的难点在于计数排序。 计数排序详解&#xff1a;C算法之计数排序 为了尽可能多的买到雪糕&#xff0c;我们选择从价格低的雪糕开始买&#xff0c;统计能够买到的雪糕…

SQL基础语法总结(查询)

学习网站&#xff1a;https://www.w3schools.com/sql/&#xff0c;提供在线编程 以下内容仅SQL常见语法总结 数据 Customers表 Products表 OrderDetails表 Orders表 Shippers表 Employees表 选择查询 SELECT select语句用来从头数据库中选择数据 SELECT column1, column2,…

基于SSM的大学校医管理系统

基于SSM的大学校医管理系统、学校医院管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 登录系统 用户界面 管理员界面 摘要 大学校医管理系统…

Linux系统编程:进程part_2(信号相关)

前言 这一节内容我没怎么认真写&#xff0c;就是纯当草草过了一遍&#xff0c;这部分不是很重要当然能掌握肯定更好。 更多的是有个印象然后知道遇到这样的问题能回想起来知道怎么解决即可&#xff08;虽然不太可能遇到&#xff09;。 信号量 实现PV操作 P&#xff1a;测试并…

springboot生成二维码的正确姿势-附视频附源码

二维码的原理是什么&#xff0c;如何保证不重复&#xff1f;你有没有想过这样一件事&#xff0c;二维码是实现原理是什么&#xff1f;如何保证各个平台的二维码是唯一的&#xff1f;就算你的程序停止运行&#xff0c;但是你的二维码依然存在。设计上要保证唯一性&#xff0c;比…

ubuntu启动模式介绍以及如何进入单用户模式和恢复模式

Ubuntu操作系统提供了多种启动模式&#xff0c;每种模式都有不同的用途和功能。下面将深入介绍Ubuntu的几种启动模式&#xff1a; 正常启动模式&#xff08;Normal boot&#xff09;&#xff1a;这是默认的启动模式&#xff0c;也是大多数用户使用的模式。在正常启动模式下&am…

Linux 救援模式

Linux突然坏了 第三次坏了 第一次是找不到盘&#xff0c;修复好了 第二次是找不到卷&#xff0c;但是能启动&#xff0c;启动界面选择救援模式&#xff0c;可以正常使用 第三次&#xff0c;尝试修复卷&#xff0c;启动后&#xff0c;找不到文件系统了&#xff0c;只能从光盘…

【C++】继承和多态常见的问题

一、概念考查 1、下面哪种面向对象的方法可以让你变得富有( A ) A. 继承 B. 封装 C. 多态 D. 抽象 继承机制是面向对象程序设计使代码可以复用的最重要手段&#xff0c;继承是类设计层次的复用。 2、( D )是面向对象程序设计语…