目录

1.所以进程的地址空间是什么呢?

2.mm_struct内部有什么?

3.虚拟地址空间与物理内存如何关联

页表

4.为什么设计这样一个进程地址空间,不让程序直接访问内存

Q:为什么子进程修改值以后,地址还是相同?

Q:常量字符串为什么地址相同


1.堆是堆,栈是栈,堆栈是栈

2.经过验证,C/C++的程序地址空间就是如图所示,栈区是往低地址方向增长的。

子进程中对val进行修改,会发生写时拷贝。从而拷贝一份数据到另外的地方,变量的值是不一样的,但是他们两个变量对应的地址却是一样的,说明这个地址不是真正的物理地址,而是虚拟地址。

1.所以进程的地址空间是什么呢?

A:实际上是一个结构体,里面存放了一个进程不同分区的虚拟地址空间。(不是真实的物理空间)

每个进程都有一个地址空间,那么操作系统要管理,所以要先描述后管理,所以为每个进程定义一个mm_struct存放该进程的地址空间(里面有各个分区的起始和结束位置,总大小等)。

因为这个进程地址空间是属于这个进程的,在进程的task_struct里面会存放指针指向这个mm_struct,通过task_struct可以找到mm_struct


2.mm_struct内部有什么?

有代码段,常量区,堆区,栈区的起始位置和结束位置等信息。

虽然这里只有start和end,但是每个进程都认为mm_struct代表整个内存,且所有的地址都是0x00 00 00 00 (1共1字节)到0xFF FF FF FF,这些地址也就是虚拟地址

每个进程都认为地址空间的划分是按照4GB空间划分的(即每个进程都认为自己有4GB的空间)但是实际上物理内存可能只有1G

struct mm_struct
{unsigned int code_start;unsigned int code_end;unsigned int init_data_start;unsigned int init_data_end;unsigned int uninit_data_start;unsigned int uninit_data_end;unsigned int heap_start;unsigned int heap_end;//......
}

3.虚拟地址空间与物理内存如何关联

mm_struct相当于描绘了一个4GB的虚拟地址空间,里面对应的地址叫做虚拟地址。(mm_struct内部并不是真的有这么大的地址空间,而是用起始位置和结束位置来表示的)

那么物理地址和虚拟地址如何映射到一起的呢? ————使用页表+MMU(一种硬件,称为内存管理单元,用于查找页表,一般集成在CPU中)

页表

页表是操作系统为每个进程维护的一张表,存放着虚拟地址和物理地址(就像hash表),用于根据虚拟地址去找到对应的物理地址。(将虚拟地址映射到对应的物理地址)


4.为什么设计这样一个进程地址空间,不让程序直接访问内存

原因一:操作系统可以对进程进行风险管理(权限管理),保证物理内存数据安全

原因一:如果进程直接访问物理内存的话,无法保证物理内存中的数据安全,通过添加一层软件层,操作系统可以完成有效的对进程操作内存进行风险管理(权限管理)(比如通过页表转地址,你有没有权限访问这个区域里面的内容,有没有越界访问等),本质目的是为了保护物理内存以及各个进程的数据安全!

你虚拟地址转换成物理地址的时候,是交给操作系统来转的,它就可以决定帮不帮你转,转完以后你有没有权限可以访问。

const char* str = "zebra"

*str = "hello";

e.g:像这个地方,我们无法对常量区的内容进行修改,实际上是因为OS给你的权限只有r权限,这个和页表也有关系,你在使用str指针的时候,实际上也是使用了虚拟地址,在通过页表转换为物理地址的时候操作系统就会发现你没有权限对常量区的内容进行修改,所以就拒绝你的这次修改。

原因二:屏蔽内存申请内存的过程,将普通进程读写内存和OS对内存进行管理在软件层面上进行解耦(申请的时候只是划分虚拟地址空间,访问内存时才真正开辟物理内存,你申请了空间不使用的话,操作系统可以把空间给其他人用,等你真的要使用了才为你开辟内存)

在OS角度,如果空间立马给你,意味着整个系统会有一部分空间,本来可以给别人立马用的,现在却可能被你闲置着,造成了空间浪费。

一开始进程申请了空间的时候,操作系统并不会马上将物理空间分配给进程,而是给进程划分了一片虚拟内存空间(比如在mm_struct中将heap_end+100),当进程真正要读取这段空间的时候,操作系统说等等(缺页中断),然后为进程开辟一片物理空间给进程使用(基于缺页中断进行物理内存申请)。

原因二:将内存申请和内存使用的概念在时间上划分清楚(申请的时候申请,使用的时候使用,等你使用了我才真的为你开辟内存,类似写时拷贝),通过虚拟地址空间,来屏蔽内存申请内存的过程,将普通进程进程读写内存和OS进行内存管理操作,进行软件层面上的分离(解耦)

e.g.:比如现在内存已经满了,你还要内存,我操作系统仍然可以给你(虚拟),然后执行对应的内存管理算法释放一些内存,等到你要用的时候,我把空间给你

原因三:不同进程中每个区域的相对位置比较确定,CPU可以以统一的视角看待内存;程序的代码数据可以加载到物理内存的任意位置

如果没有进程的地址空间,CPU没法以统一的方式去寻找每个进程的起始位置。

e.g:比如CPU执行不同进程,每个进程一个main函数的话,CPU每次开始执行进程的时候只需要从虚拟地址0x1234开始执行,根据不同进程的页表可以找到对应进程main函数的物理地址(每个进程的页表中,虚拟地址都是0x1234),这样CPU执行多个进程的时候就很方便。

原因三:有了地址空间以后,站在CPU和应用层的角度,进程统一可以看做统一使用4GB空间,(1).而且不同进程中每个空间区域的相对位置(比如堆栈大概在哪个位置),是比较确定的,CPU可以以统一的视角看待内存,执行进程/读取数据的时候会方便许多。(CPU执行一个进程的时候,可以知道堆,栈,常量区大概在地址空间的哪个位置,因为每个进程的地址空间都是一致的)

对操作系统来说,(2).程序的代码和数据可以被加载到物理内存的任意位置,只需要通过进程的页表将其位置和对应的地址空间映射起来就行,大大减少了内存管理的负担。


Q:为什么子进程修改值以后,地址还是相同?

因为这个地址是虚拟地址,子进程和父进程中这个变量的物理地址是不相同的。

子进程的创建是以父进程为模板的,所以子进程的进程地址空间和页表也是继承的父进程的,所以g_val的虚拟地址都是一样的。

子进程修改了g_val的值以后,发生了写时拷贝,为子进程重新开辟了一块物理空间,将父进程g_val的值拷贝进入这个物理空间,然后修改子进程页表中原来g_val的虚拟地址和物理地址的映射关系,将物理地址改为新开辟内存的地址。但是此时虚拟地址没有发生变化,从而也就发生了这种情况。

代码共享一份的实现也很简单,只要将父进程和子进程页表中存放代码的虚拟地址映射到同一块物理空间即可。


Q:常量字符串为什么地址相同

char* str = "hello world";

char* p = "hello world";

  • hello这个字符串常量字符串,是只读的,所以操作系统只会保存一份,存放在常量区
  • 字符串常量是一个表达式,表达式的值就是这个字符串常量第一个字母对应的地址,这是一个虚拟地址,然后把这个地址给p和str
  • 所以最后p和str的值打印出来都是相同的,表示的都是string这个字符串的虚拟地址
  • 虽然p和str两个指针变量的值是相同的,但是他们的虚拟地址是不相同的

Linux操作系统~什么是虚拟地址?深度剖析进程地址空间相关推荐

  1. [入门篇]Linux操作系统fork子进程的创建以及进程的状态 超超超详解!!!我不允许有人错过!!!

    目录 0.前言 1.fork()创建子进程讲解 1.1fork()的简单介绍 1.2 创建子进程详解 1.2.1 如何理解fork创建子进程 1.2.2 子进程的PCB以及子进程的代码和数据 1.2. ...

  2. Linux操作系统原理与应用03:进程

    目录 1. 进程简介 1.1 程序和进程 1.2 进程的定义 1.2.1 正文段 1.2.2 用户数据段 1.2.3 系统数据段 1.3 进程的层次结构 1.3.1 进程的亲缘关系 1.3.2 进程树 ...

  3. linux中把程序启到前台,Linux操作系统桌面应用与管理Q4rw2进程与作业管理-PPT精品文档.ppt...

    红旗Linux,情境四任务2:进程和作业管理,任务2-1,了解进程管理知识用命令实现进程管理,Linux进程管理,WINDOWS?任务管理器LINUX利用命令管理进程包括前.后台进程的管理以及终止等, ...

  4. 单装linux系统安装教程,深度linux操作系统安装图文教程

    深度linux操作系统怎么安装呢?深度linux操作系统为所有人提供稳定.高效的操作系统,强调安全.易用.美观;具体深度linux操作系统安装方法,我们一起来了解一下. ps:如有其它有关操作系统问题 ...

  5. Linux进程地址空间学习总结

    Linux内核--内核地址空间分布和进程地址空间 http://www.cnblogs.com/bizhu/archive/2012/10/09/2717303.html 内核地址空间分布 直接映射区 ...

  6. linux 进程地址空间的一步步探究

    我们知道,在32位机器上linux操作系统中的进程的地址空间大小是4G,其中0-3G是用户空间,3G-4G是内核空间.其实,这个4G的地址空间是不存在的,也就是我们所说的虚拟内存空间. 那虚拟内存空间 ...

  7. Linux进程地址空间探究

    我们知道,在32位机器上linux操作系统中的进程的地址空间大小是4G,其中0-3G是用户空间,3G-4G是内核空间.其实,这个4G的地址空间是不存在的,也就是我们所说的虚拟内存空间. 那虚拟内存空间 ...

  8. Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的

    文章目录 (1)旧知回顾 (2)程序地址空间? A:同一个地址有两个数据? B:物理地址和虚拟地址 C:进程地址空间及作用 D:进程地址空间如何工作 (1)旧知回顾 学习C/C++总免不了这张图 这张 ...

  9. Linux操作系统下Moodle平台的搭建

    转自http://fuwu.aieln.com/info/show/711/ 软件下载地址(Moodle2.2.2(Build:20120312)):http://bbs.aieln.com/arti ...

最新文章

  1. old DIB in res\*.ico
  2. Markdown 语法介绍
  3. 【JavaScript】Document对象学习
  4. 存储过程排版工具_安利一款比Evernote更为实用的云笔记工具,不容错过
  5. Redis分布锁原理简介和实现过程
  6. 深度学习“三巨头”、图灵奖得主 Yann LeCun:我没有天赋,所以才追随聪明人...
  7. python入门必备知识总结
  8. MapReduce+MapReduce执行过程(四)
  9. 【 Codeforces Round #551 (Div. 2) D】Serval and Rooted Tree【树形DP】
  10. 产品 电信nb接口调用_NB-IOT开发流程---基于中国电信物联网平台实现平台对接
  11. 【Unity编辑器扩展】查找场景和资源内挂载某脚本的所有对象
  12. 计算机常见故障判断与排除,电脑常见故障诊断与排除从新手到高手
  13. 如何通过付费咨询,薅知乎的羊毛?
  14. 机器学习系列4 使用Python创建Scikit-Learn回归模型
  15. HTML、CSS面试题
  16. Opengl ES之矩阵变换
  17. SQL 两行两列显示一行四列或一行两列
  18. 【Python模块】matplotlib 柱状图
  19. 国内不翻墙调用chatgpt api
  20. insmod过程详解

热门文章

  1. 【clion】Clion安装与配置
  2. B站尚硅谷React入门教程
  3. c语言ftell的作用,C语言的文件随机访问fseek()和ftell()函数
  4. 未来趋势:区块链溯源技术
  5. Android GoogleMap接入
  6. Report中的Drill down
  7. killall 命令的用法
  8. 软件体系结构与软件架构解析
  9. 花了一些力气研究aircv,搞一个后台找图识图的DEMO
  10. 二、zookeeper客户端使用和集群特性