IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 进程地址空间 -> 正文阅读

[C++知识库]进程地址空间

前言

你可能在C语言的学习中看过C程序的地址空间,但是今天以后它应该叫做进程地址空间。
程序地址空间
1,你最熟悉的应该是栈和堆,当时你可能只了解了下面的部分,实际上上面的部分是内核区域。
2,还有一点要注意的是,代码段并不是从0000。。。开始的,虽然图上是这样画的。
3,这张图清晰的表明了C程序运行的数据分配。你可能被告知上面的是内存的划分,但是接下来的讨论可能会让你大开眼界(相信我,你会的)。

地址空间

首先要说明的是地址空间这个概念,什么是地址空间呢?一块地址空间每个部分都有被使用吗?不是的,地址空间只是划分出一段范围,表示所有的程序只能在这段空间内活动,这并不表示每个部分都有被使用。

进程地址空间不是物理内存 + 矛盾的栗子

下面的代码可能让人难以理解:

栗子

上面的栗子的作用是父进程fork了一个子进程,它们都有一个val,父进程输出val之前先睡3秒,保证父进程在子进程后面执行。此时val已经被改变,我们来看看这个进程的结果。
ret
可以看到一个奇怪的现象:父子进程的val是不同的,但是它们的地址相同。进程地址空间是内存吗?如果是物理内存,那么一块空间不可能在同一时间有不同的值!!所以进程地址空间不是内存。进程地址空间只是夹在进程的PCB和物理内存中间的虚拟的东西。
父子进程

task_struct中夹着的东西就是进程地址空间,每一个task_struct都配一个进程地址空间,而进程地址空间通过某种映射关系与物理内存发生联系。现在我们来解决这个程序的疑惑。一开始的时候父进程在它的进程地址空间给val分配了一块空间,然后fork之后,子进程也会复制一份跟父进程类似的进程地址空间,而它自然也把val在进程地址空间的位置复制过来了,所以父子进程的val地址相同。刚复制过来的时候,由于子没有修改数据内容,所以操作系统就把父子的val映射到同一块物理内存。但是当val变成1000时,由于进程有独立性,它是数据独有,所以为了保证父子进程互不影响,操作系统会在物理内存中另外找一份空间给子进程val,注意,这里子进程的task_struct和他的虚拟地址的映射不会改变!!所以这就造成了一种现象:地址相同,值不同。
变化

为什么需要进程地址空间?

1,如果没有进程地址空间,那么你直接操作的就是物理内存,那么你的失误操作就可能影响到内存的安全,或者影响到别的进程。比如你使用了野指针,或者你的数组越界,访问到别的进程的空间,那就完了。而增加了进程地址空间,由用户直接访问内存变成由操作系统去访问内存,操作系统就会直接pass掉对内存有害的操作。
2,考虑这样一种情况,内存一共4G,
情况
A进程2G,B进程1G,此时还剩下1G,但是A和B进程不是连续存放的,导致剩下的空间不是连续的,如果此时来了一个1G的进程想要连续的空间(比如开辟数组),此时虽然你的内存足够,但是无法使用。这就造成了内存的浪费。如果使用虚拟地址空间,那么从pcb的角度来看,虚拟地址空间是连续的,你就可以随便使用,但是你可以改变映射关系,使得连续的虚拟空间映射到不连续的物理内存,充分利用内存的空间。
3,上面就是我们需要进程地址空间的原因之二。这个进程地址空间的设计有点类似shell的思想,封装一层,在C++中这种思想比比皆是。

进程地址空间如何映射到物理内存?

这里就要介绍一种叫做页表的东西,进程地址空间实际上是通过页表映射到物理内存上的。页表中记录了虚拟内存和物理内存的地址。
页表

页表对内存的权限管理

这里就要问道几个问题了,既然虚拟地址空间会保护内存,那么我们编写C/C++代码时为什么还有注意野指针,越界之类的问题?答案是,虽然一定程度上保护了内存,但是还是可能映射到非法的物理内存上。还有我们常说的代码时可读不可写的,string时可读的,这些的权限限制是如何搞定的呢?没错,页表的又一功能就是限制访问内存的权限:保证只读的数据只有读权限,只写的数据只有写权限。而且如果你使用野指针或者非法数据,由可能系统根本不会帮助你映射到页表上,即使映射到页表上,映射到了非法的内存,你也不对这块内存具有访问权限!!! 所以可以解释一种现象,有的时候你写非法代码系统竟然允许,有的时候会崩溃。因为允许的时候,你映射的非法内存的写权限和读权限被允许,崩溃的时候则是权限不够,被系统pass掉了。而所谓的只读,只写,就是页表规定的。

管理进程地址空间

系统中一般都有多个进程,也就会有多个进程地址空间,那么这些数据需要被管理。怎么管理呢?当然是先描述,再组织。上面说过进程地址空间不是内存,它实际上也是结构体!! 名字叫做struct mm_struct。而且我们知道进程地址空间是分段的,堆区,栈区等等。那么体现在结构体中是怎样的呢?在linux中mm_struct的源码中,是按照范围划分的。比如一段进程地址空间大小为100,那么我规定好代码段的begin和end就好了。比如我规定begin是0,end是50,那么代码段的范围就是[0,50].

 // mm_struct的部分源码 , 2.6版
mm_struct{
	// ...
	unsigned long start_code, end_code, start_data, end_data; //代码段和数据段的开始和结束
	unsigned long start_brk, brk, start_stack; //因为堆,栈是浮动的空间,所以没有end。
	unsigned long arg_start, arg_end, env_start, env_end; //命令行参数和环境变量范围的开始和结束
	// ...
}

可以看到源码中的描述方式就是使用整数描述了各段的开始和结束,这样就划分出不同的区域供使用。申请空间的本质是向内存索要空间,得到物理内存,然后在找到未使用的虚拟地址,建立映射关系,返回虚拟地址即可。
这就像大学里上课,老师就是pcb,学生在教室里可以随便坐,但是每次老师点名用的名单不变,名单就相当于进程地址空间,而物理内存就是教室。老师并不关系你坐在哪,我只要知道名单就够了,然后按照顺序点名。

其他的进程信息

内存指针:pcb中的内存指针可以理解为指向内存中该进程代码的指针,帮助pcb找到代码。
程序计数器:在pcb中,主要用来记录下一条指令的地址。
上下文数据:一个进程在cpu中运行时,会产生大量临时数据,当这个进程的时间片结束或者资源被抢占时,需要存储临时数据,这些上下文数据就存在pcb中。

总结

进程就是task_struct + 程序的数据&&代码 + mm_struct和页表。task_struct中包含了进程的各种信息,当进程被加载到内存中,它的task_struct被创建出来加入操作系统的管理队列,然后分配内存的时候mm_struct和页表也被创建,方便和安全的对内存管理。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 11:43:10  更:2021-09-03 11:44:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:55:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码