【Linux】虚拟地址空间

这篇具有很好参考价值的文章主要介绍了【Linux】虚拟地址空间。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、引入

对于C/C++程序,我们眼中的内存是这样的:
【Linux】虚拟地址空间

我们利用这种对于与内存的理解看一下下面这段代码:

【Linux】虚拟地址空间

运行结果:

【Linux】虚拟地址空间

观察父子进程中 val 变量的值,以及 val 的地址,我们发现父子进程中 val 的地址都是同一个地址 但是 val 的值并不相同,这是什么意思???内存中同一个地址却存放了两个不同的变量值?这显然是不可能的!地址具有唯一性,地址处存放的数据也具有唯一性!

一种合理的解释是:我们在C程序中所用到的地址的一个虚拟地址,并不是真正的物理内存地址!

在C/C++程序中我们所使用到的地址都是虚拟地址,这些虚拟地址组合起来就形成了虚拟地址空间,在Linux中虚拟地址空间被一个叫struct mm_struct的结构体所管理。

那么我们想知道这个程序的虚拟地址空间到底虚拟了多大的内存呢?
答案是:每个进程所能访问的最大的虚拟地址空间由计算机的硬件平台决定,具体地说是由 CPU 的位数决定的。

比如 32 位的 CPU 决定了虚拟地址空间的大小为 [ 0 , 2 32 − 1 ] [0 ,2^{32}-1] [02321],即 0x00000000 - 0xFFFFFFFF,也就是我们常说的 4 GB 虚拟内存空间。如果是 64 位的CPU,那么寻址范围是 [ 0 , 2 64 − 1 ] [0 ,2^{64}-1] [02641],即 0x0000000000000000 - 0xFFFFFFFFFFFFFFFF,共有 17 179 864 184 GB。

【Linux】虚拟地址空间

所以开头我们看到的内存其实是操作系统为我们程序虚拟的虚拟地址空间,这个虚拟地址空间的分配如下:

【Linux】虚拟地址空间

二、虚拟地址与物理内存的联系

经过上面的介绍我们知道了原来我们认为内存其实是虚拟地址空间,但是我们的代码与数据是要真真实实的存储在物理内存中,虚拟地址空间里面存放的仅仅是一些代码和数据的虚拟地址,那么我们是怎么通过虚拟地址来找到物理内存中的代码与数据呢?

答案是:通过一种数据结构——页表和一种硬件——MMU(内存管理单元),通过页表来进行虚拟地址与物理地址一 一对应从而找到相应的代码与数据

【Linux】虚拟地址空间

明白了这些后我们再来看开头的问题,为什么同一个地址存放的是不同的数据?

【Linux】虚拟地址空间
在父进程刚开始创建子进程时,子进程是的大多数数据(如:task_struct , 虚拟程地址空间等数据)都是以父进程为模板创建而来的,因此在最初时父进程与子进程的虚拟地址空间和页表是相同的,然后父进程尝试去修改变量 val 的值,由于进程具有独立性,操作系统不能让父进程的修改影响到子进程,于是发生了写时拷贝,操作系统先在物理内存中重新找一块空间保存了父进程修改后的 val 值,然后将父进程页表中对应物理地址进行更改。

注意:虚拟地址不更改,只改变物理地址!因为物理地址实实在在的变化了,虚拟地址没有必要更改。

三、为什么要有虚拟地址空间

可能你会觉得为什么要有虚拟地址空间呢?我们的进程为什么不直接使用物理地址呢?直接使用物理地址还能减少中间层提高运行的效率。

要回答这个问题我们可以从下面几个的角度来回答:

  • 防止地址随意访问,保护物理内存与其他进程

如果我们没有虚拟地址空间,当我们在内存中运行两个程序时,如果其中在一个进程中发生了越界访问,那么就有可能访问到其他的进程,这样进程之间就会互相影响了,进程的独立性就无法保证了
【Linux】虚拟地址空间
有了虚拟地址空间以后我们便可以通过页表来进行判断越界后的地址与接下来的操作是否统一的,如果是统一的便进行映射。

  • 将进程管理和内存管理进行解耦合!
    这里我们先来谈一谈malloc的本质,malloc函数是在调用后向OS申请内存,操作系统立马给你,还是需要的时候在给你呢 ?
    答案是:在你需要的时候给你!!!
    那么为什么会是这样的呢?因为操作系统要管理好所有的软硬件资源,OS一般不允许任何的浪费或者不高效的行为出现!

    我们在申请完内存以后并不一定立马使用,在你申请成功之后,和你使用之前,就以一段小小的时间窗口,这个空间没有被正常使用,但是别人用不了,于是这块空间就处于了闲置状态! 这是OS不允许的!

    于是我们在用malloc申请空间时OS其实是先通过task_struct找到虚拟地址空间和管理虚拟地址空间的mm_struct结构体,然后对于虚拟地址空间的内容进行修改并将mm_struct里关于堆区的范围进行修改,然后页表中关于虚拟地址的部分的内容会进行增加,但是新增的虚拟地址去没有与实际的物理地址建立映射关系,只有当你要使用你申请的空间时,OS才会真正的为你分配空间,并将页表中新增的虚拟地址对应的物理地址的映射关系建立起来!这时OS才真正的完成了内存分配!
    【Linux】虚拟地址空间

这个时候,我们将页表从中间一分为二,左边就是进程管理,右边就是内存管理,进程管理发生错误不影响内存管理,内存管理出现错误不影响进程管理,这样我们就实现了进程与内存管理的解耦合

【Linux】虚拟地址空间

  • 可以让进程以统一的视角,看待自己的代码和数据!
    在这里我们来讨论一下我们的程序在被编译的时候,没有被加载到内存,我们的程序内部有没有地址呢?
    答案是:有的!

    我们的C/C++程序在被编译时就采用了虚拟地址空间的方式进行编译,并将数据按照代码段,已初始化数据段,未初始化数据段等方式进行分类存储。当我们的程序加载进内存时,我们的程序可以分批式的将程序的数据段,代码段,分批的加载进地址空间中。
    注意:编译好的程序并没有堆区和栈区,只有加载进内存时形成进程时才有堆区与栈区!

有了地址空间之后我们的进程便不再关心代码与数据究竟在内存中的哪里,我们每个进程都是以统一的视角——虚拟地址空间的方式来待自己的代码与数据。文章来源地址https://www.toymoban.com/news/detail-404697.html

到了这里,关于【Linux】虚拟地址空间的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux系统化学习】进程地址空间 | 虚拟地址和物理地址的关系

    ========================================================================= 个人主页点击直达: 小白不是程序媛 Linux专栏: Linux系统化学习 代码仓库: Gitee ========================================================================= 目录 虚拟地址和物理地址 页表 进程地址空间 进程地址空间存在的意义 我们在学

    2024年02月05日
    浏览(44)
  • 【Linux-14】进程地址空间&虚拟空间&页表——原理&知识点详解

    前言 大家好吖,欢迎来到 YY 滴 系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁 主要内容含: 欢迎订阅 YY 滴C++专栏!更多干货持续更新!以下是传送门! YY的《C++》专栏 YY的《C++11》专栏 YY的《Linux》专栏 YY的《数据结构》专栏 YY的《C语言基础》专栏 YY的《初学者易

    2024年04月29日
    浏览(44)
  • 【看表情包学Linux】进程地址空间 | 区域和页表 | 虚拟地址空间 | 初识写时拷贝

       🤣  爆笑 教程  👉 《看表情包学Linux》👈   猛戳订阅     🔥 💭 写在前面: 本章核心主题为 \\\"进程地址空间\\\",会通过验证 Linux 进程的地址空间来开头,抛出 \\\"同一个值能有不同内容\\\" 的现象,通过该现象去推导出 \\\"虚拟地址\\\" 的概念。然后带着大家理解为什么虚拟地

    2024年01月20日
    浏览(57)
  • Linux内核源码分析 (B.2)虚拟地址空间布局架构

    Linux内核只是操作系统当中的一部分,对下管理系统所有硬件设备,对上通过系统调用向 Library Routine 或其他应用程序提供API接口。 内存管理可以通过以下三个维度进行介绍: 用户空间 相当于应用程序使用 malloc() 申请内存,通过 free() 释放内存。 malloc() / free() 是 glibc 库的内

    2024年02月09日
    浏览(60)
  • [Linux]环境变量 进程地址空间(虚拟内存与物理内存的关系)

    hello,大家好,这里是bang_bang,今天我们来讲一下语言层级上的程序地址空间和系统层级上的进程地址空间的区别,在下面中我举的例子会设计到环境变量,所以开篇我先讲讲环境变量。 目录 1️⃣环境变量 🍙 基本概念 🍙环境变量相关命令 🍥查看环境变量echo 🍥添加全局环

    2024年02月15日
    浏览(50)
  • 【Linux】程序地址空间?进程地址空间

    了解进程的运行:  运行结果:我们会发现这打印的结果乱七八糟,因为它也不知道什么时候该干什么  我们让代码睡眠1秒:打印的结果就正常了  以前我们学习的内存管理(程序地址空间):  为了验证上面虚拟地址,我们运行下面代码: (这种问题出现的原因在下面的为

    2024年02月13日
    浏览(89)
  • 【Linux】程序地址空间

    首先引入地址空间的作用 我们发现,但我们子进程修改全局变量g_val的时候,父进程的g_val没有受到影响,但是他们的地址都是一样的,这是为什么呢? 由此我们知道,这里的地址绝对不是物理内存的地址,而是虚拟地址(线性地址);并且几乎所有语言,如果有地址的概念

    2024年02月13日
    浏览(30)
  • Linux--程序地址空间

    📘北尘_ :个人主页 🌎个人专栏 :《Linux操作系统》《经典算法试题 》《C++》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 @[TOC](文章目录) 我们在讲C语言的时候,老师给大家画过这样的空间布局图 下图是内存吗?答案不是,它是进程/虚拟地址空间。 可是我们对他

    2024年02月03日
    浏览(30)
  • [Linux 进程(五)] 程序地址空间深度剖析

    Linux学习路线比较线性,也比较长,因此一个完整的知识点学习就会分布在两篇文章中,没有连贯起来,订阅的朋友谅解一下,再次感谢订阅! 上一篇文章最后讲到了程序地址空间分布,大家可以先复习一下上一篇文章:程序地址空间的初认识 本片我们深度学习一下程序地址

    2024年01月19日
    浏览(39)
  • [Linux 进程(四)] 再谈环境变量,程序地址空间初识

    上一篇我们讲了环境变量,如果有不明白的先读一下上一篇文章:环境变量讲解 本篇文章我们继续完善环境变量这章剩下的内容,以及main函数第三个参数的详解,进程地址空间的初始。 看完上一篇文章的同学,肯定知道了如何查看环境变量,命令行输入 env: 我们查看一下

    2024年01月18日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包