虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

这篇具有很好参考价值的文章主要介绍了虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

💐专栏导读

🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

🌸专栏简介:本文收录于 Linux从入门到精通,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

🌸相关专栏推荐:C语言初阶系列C语言进阶系列C++系列数据结构与算法

💐文章导读

本章我们将对程序地址空间进行讲解,理解虚拟地址的运作逻辑,认识虚拟地址与物理地址如何建立联系以及虚拟地址存在的意义~

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

🐧引例

——为什么一个变量拥有两个不同的值?

之前在第一次认识fork时,我们就知道fork是用来创建子进程的。先来感受一段代码,我们定义一个全局变量g_val,在父进程与子进程中分别查看g_val的值以及它的地址。

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

int g_val = 100;

int main()
{
  pid_t id = fork();

  if(id < 0)
  {
    perror("fork");
    return 0;
  }
  else if(id == 0)
  {
    // 子进程
    while(1)
    {
       printf("我是子进程,pid=%d,ppid=%d,g_val=%d,&g_val=%d\n",getpid(),getppid(),g_val,&g_val);
       sleep(1);
    }
  }
  else 
  {
    // 父进程
    while(1)
    {
      printf("我是父进程,pid=%d,ppid=%d,g_val=%d,&g_val=%d\n",getpid(),getppid(),g_val,&g_val);
      sleep(1);
    }
  }

  return 0;
}

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

如图所示,我们发现父子进程打印的值与地址完全相同。接着再来做测试,倘若在子进程中改变g_val的值,那么父进程中的g_val会不会一起跟着变化呢?

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

int g_val = 100;

int main()
{
  pid_t id = fork();

  if(id < 0)
  {
    perror("fork");
    return 0;
  }
  else if(id == 0)
  {
    // 子进程
    while(1)
    {
       printf("我是子进程,pid=%d,ppid=%d,g_val=%d,&g_val=%d\n",getpid(),getppid(),g_val,&g_val);
       sleep(1);
       g_val = 200;
    }
  }
  else 
  {
    // 父进程
    while(1)
    {
      printf("我是父进程,pid=%d,ppid=%d,g_val=%d,&g_val=%d\n",getpid(),getppid(),g_val,&g_val);
      sleep(1);
    }
  }
  return 0;
}

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

结果如图所示,我们发现在子进程中修改变量的值,并不会影响父进程。我们知道进程具有独立性,父子进程之间互不影响好像也能说得过去,但是两个进程中g_val的地址都是相同的,一个地址怎么能存两个不同的值呢只能说明这两个地址其实并不是真正的物理地址。

对此我们可以得出结论:

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量;
  • 但它们地址值是一样的,说明该地址绝对不是物理地址!
  • 在Linux地址中,这种地址叫做 虚拟地址
  • 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理。

接下来我们就来看看何为虚拟地址,它又为什么而存在。

🐦进程地址空间

或许我们之前都是这么看待内存的——
虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...
如图所示,我们以前经常把内存区域作划分,并强调哪些变量应该存储在内存的哪些区域,其实这些区域的划分都是虚拟内存。

那么这些不同的区域(栈区、堆区、常量区等)又是如何进行划分的呢?

  • 进程地址空间本质上就是一个内核数据结构——struct mm_struct,由操作系统所管理。

我们知道内存的地址是连续的,也就意味着内存空间是一种线性结构。OS通过对内核数据结构的划分完成对内存区域的划分,例如:

struct mm_struct
{
	// 代码区
	long code_start; // [0,100]
	long code_end;
	// 初始化区域
	long init_start; // [200,500]
	long init_end;
	// 栈区
	long stack_start; //[x,x+n]
	long start_end;
	//...
}

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

虚拟地址是虚拟的、不存在的。可是我们所写的那些变量常量等等总得找个地方存起来吧。它们可都是实实在在的存储在物理内存上的。难道虚拟内存所有的内容都与物理内存一一对应吗?那当然是不可能的。

其实在虚拟内存与物理地址之间还存在这一个媒介——页表。它负责将虚拟地址与物理地址形成一种映射关系。

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

🔔回答引例中的问题

有了上面的概念,我们现在可以清楚。子进程是被父进程创建出来的,所以子进程没有自己的代码和数据,只能继承自父进程。所以子进程与父进程中的g_val地址相同,现在我们知道这两个地址其实都是虚拟地址。

  • 父进程与子进程中的g_val会被页表映射到同一个物理地址。

有的小伙伴可能会疑问,不对呀,那这样刚才岂不是白讲了。这样的话我们改变子进程中的g_val,父进程不也会跟着变吗?

答案是,还差非常重要的一点没有提出来——写时拷贝

🔓写时拷贝

由于父进程和子进程的g_val一开始内容是完全相同的,没必要再新开一块空间存储一个重复的数据,避免浪费。所以,只要我们不修改g_val的值,两个g_val存在共用一块内存区域是合理的。

但是,一旦有一方需要修改g_val的值,为了避免一方修改会影响到另一方,此时OS会在内存中重新找到一块区域,将修改后的值放进去,并让页表将虚拟地址从旧的物理地址,映射到新的虚拟地址。这就叫做写时拷贝

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

  • 写时拷贝概念图

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

🐦虚拟地址存在的意义

举个例子,假设现在有100个班级,需要去一个水果商店免费水果。现在校长把任务交给了这100个班主任,让他们自行组织安排。班主任们并不需要考虑所有学生的人数或者男女比例或者强壮程度等等,只需要安排好自己班级的每个学生应该完成什么任务。这样,每个班主任各自拟好了一个任务安排表,并把它交给商店老板。商店老板会根据任务安排表,分配好每个班级应领取的水果数量、种类等等,到时候直接同时学生们过来取走即可。

在这个小例子中,学生就相当于代码和数据任务安排表相当于虚拟地址商店老板就相当于页表商店的水果相当于物理内存

假设不存在虚拟地址,也就是任务安排表不存在,商店老板就不能对着安排表做出规划,同学们与领取水果时,势必会杂乱无章甚至可能起了冲突。例如几个同学一起盯上了为数不多的榴莲…况且,同学们不知道商店中哪些水果可以拿。哪些已经被顾客预定了,不能拿…

对比这个例子,虚拟地址的作用有:

  • 防止地址随意访问,保护物理内存与其他进程(防止争抢水果)
  • 将进程管理与内存管理进行解耦合(班主任管学生,商店老板管水果)
  • 可以让进程以统一的视角看待自己的代码和数据(每个班主任只管自己的学生)
🔓malloc的本质

站在一个进程的角度

在很多时候,我们malloc申请了一块内存空间(现在我们知道这其实是虚拟内存),并没有立即对它进行使用,但是这块空间已经在某个变量的名下了,此时这块空间是不能再被其他变量所占用的,这是合理的。

站在OS的角度

那么当一个进程向OS申请内存时,请问OS是直接给它呢?还是在进程需要用的时候再给它呢?答案是在需要时再给它。

因为OS不允许有任何的浪费或者不高效的行为。假设进程一申请内存,OS就给它分配内存,但是进程又暂时不用。那么它自己不用也就算了,别的进程也用不了。一个进程这样做也就罢了,当大量的进程都这样做时就会造成严重的浪费与效率低下。

  • 其实,当我们的程序在编译完成后,就已经按照虚拟地址对代码和数据进行编制了

本章的内容就到这里了,如果觉得对你有帮助的话就支持一下博主吧~

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...
虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

点击下方个人名片,交流会更方便哦~
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓文章来源地址https://www.toymoban.com/news/detail-456112.html

到了这里,关于虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • LAXCUS分布式操作系统存在的意义和价值

    总有一些新用户不能理解LAXCUS分布式操作系统,以及它存在的意义和价值,我这样说吧。 下图是一个图形桌面(LAXCUS的图形桌面,不是Windows、也不是Macintosh),在它后面,连着一个计算机集群(LAXCUS计算机集群),你可以通过桌面上的应用软件,去驱动这个集群上的几百台

    2024年02月16日
    浏览(46)
  • 从虚拟现实到真实现实:沉浸式体验的未来 (ps beta)

     首先,您需要创建一个免费的Adobe账户,如果您还没有一个账户的话。您可以在Adobe的注册页面上填写必要的信息来创建一个新账户。  Adobe: Creative, marketing and document management solutions login 创建账号:      编一个google邮箱,要记住。 填写名字以及生日。 地区最好填写“美国

    2024年02月15日
    浏览(53)
  • 极客蒂姆·斯威尼:用虚幻引擎,修补真实世界(下) | 人物志048

    斯威尼创办了EPIC公司,并发行了自己的游戏ZZT。那一年,他21岁。斯威尼说,21岁是个“更容易满足”的年纪,那个时候,每天的三四个订单已经足够令他欣喜若狂。“每天能赚大约100美元。在当时,这真不是一笔小钱。”斯威尼笑着说。 然而,21岁同样是个“野心勃勃”的

    2024年04月26日
    浏览(26)
  • 边缘计算:让虚拟现实变得更加真实和交互性强

    作者:禅与计算机程序设计艺术 虚拟现实(VR/AR)技术最近快速崛起,在各行各业都蓬勃发展。随着技术的进步,开发者也希望借助虚拟现实技术开发出更具身心舒适感的沉浸式虚拟世界,将虚拟现实与真实环境结合,提升用户体验和满足人的动手能力,这就是边缘计算(Edge C

    2024年02月13日
    浏览(33)
  • 哈佛大学商业评论 --- 第三篇:真实世界中的增强现实

    AR将全面融入公司发展战略! AR将成为人类和机器之间的新接口! AR将成为人类的关键技术之一! 请将此文转发给您的老板! --- 本文作者:Michael E.Porter和James E.Heppelmann 虽然物理世界是三维的,但大多数数据都被困在二维页面和屏幕上。现实世界和数字世界之间的这种鸿沟使

    2024年04月12日
    浏览(37)
  • 增强现实中的真实人/机/环与虚拟人/机/环

    在增强现实中,真实人与虚拟人、真实机器与虚拟机器、真实环境与虚拟环境之间有着密切的关系。增强现实技术通过将真实与虚拟相结合,打破了传统的现实世界与虚拟世界的界限,创造出了一种新的体验方式。真实人、真实机器和真实环境与其对应的虚拟元素之间的关系

    2024年02月03日
    浏览(45)
  • 类型“AxiosResponse<any, any>”上不存在属性“errorinfo”。ts(2339)真实有效。

    先看问题 类型“AxiosResponseany, any”上不存在属性“errorinfo”。ts(2339) 接口是返回有这个字段的,但是依然飘红,尝试了好多方法不行。 解决方法: 请求封装文件里面加 嘿嘿,解决了, 注意: 保存后可能不会立即生效,需要把当前文件关闭,再打开,就OK了。

    2024年02月16日
    浏览(35)
  • [虚幻引擎插件说明] DTOperateFile 使用蓝图操作文件

    本插件可以在虚幻里面使用蓝图文件进行读、写、移动、复制、删除等操作。 目录 1. 节点说明 Get Stat Data – 获取文件信息 Directory Exists – 判断目录是否存在 Directory Create – 创建目录 Directory Delete – 删除目录 File Exists – 判断文件是否存在 File Size – 获取文件大小 File Dele

    2024年02月17日
    浏览(80)
  • dockerfile ENTRYPOINT 执行.sh脚本提示找不到文件或文件不存在 No such file or directory

    我这里记录的是我遇到的一种特殊情况,如果你也遇到了这个问题,且都试了在百度中找到的解决方法还没有解决可以看看是不是和我遇到的问题一样。 在Dockerfile中,我ADD了两个文件,一个是jar包,一个是一个执行jar包的.sh文件 但是在使用命令: 就会提示 /bin/sh: 0: cannot

    2024年01月21日
    浏览(43)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包