目录一、C语言内存管理基础引入:从前我们知道一个指针指向的如果是一个常量字符串,那么这个就是指向的常量区,只读不可被修改,因此下面的程序会瓦解。 1、在我们C语言内存管理机制内里线性地点是有区域划分的。 我们如何验证这个区域的划分是否精确呢? 可以通过代码的方式在不同的区域创建变量然厥后取地点获取再举行比力 2、栈区和堆区是相对而行的!! 验证栈区:地点在变低 验证堆区:地点在变高 3、静态变量会被定义在全局区 只不外只会在作用域里利用。 二、fork遗留问题汗青遗留问题:为什么一个变量可以同时等于0又同时>0 ?? 实验: 我们会发现同一个地点竟然读到了不同的内容!! 如果变量的地点是一个物理地点,是绝对不大概出现这种环境的,因此我们的变量地点必然是不是物理地点!! ——>结论:我们寻常C/C++内里利用的地点全都不是物理地点,而是虚拟地点! 用户是看不到物理地点的,而OS必须要负责将我们所看到的虚拟地点转化成物理地点! 三、进程地点空间其实我们的之前所学的线性地点,并不是真正的物理内存,而是在PCB内部有一个指针指向了一块进程地点空间,然后虚拟地点会通过页表来映射到具体的物理地点。 ——>以是当我们创建出一个子进程后,他会拷贝一份和父进程一样的地点空间,然后当子进程想要修改对应的数据时,此时就会发生写时拷贝(由操作体系主动完成),也就是重新开辟空间,在这个过程当中只有页表对应的物理地点发生了变革,左边的地点空间不会有任何的感知。 3.1 什么叫做地点空间在32位的机器中,有32位的地点和数据总线,以是每一根地点总线有0或1,其实从本质上来说计算机能够识别是高低电频而并非二进制,以是1代表的是高电频,0代表的是低电频。——>这个过程就是CPU通过像内存充电的形式告诉内存我需要哪个地点,然后内存就能够通过识别高低电频,形成一个物理数据,将地点对应的数据以同样的方式交给CPU。 以是地点空间就是地点总线分列组合形成的地点的范围【0,2^32】 3.2 如何明白地点空间的区域划分?举个例子:比方说当前的桌子有100cm长,坐着小胖和小美,但是小胖常常骚扰小美,以是就在桌子中间画了一个三八线。 一人只有50cm的空间。以是从布局上就可以如下划分: 区域划分就是通过布局体内部的start和end去做划分 如何明白区域的变大或者变小呢??——>修改对应布局体内部的start和end即可 我们不但要看到地点空间的范围,我们要知道在范围内一连的空间中,每一个最小单位都可以有地点,这个地点可以被直接利用!! 3.3 什么是进程地点空间所谓进程地点空间,本质上就是一个描述进程可视化范围的地点空间内存在各种区域划分,对线性地点举行start、end即可 。本质上其实就是一个内核数据布局,和PCB一样,地点空间也是需要被/操作体系管理的:先描述再构造。 而每一个进程都有本身的进程地点空间,PCB内部有一个指针指向这块空间! 四、页表共识:现代操作体系中,险些不做浪费空间和时间的事变! 4.1 写时拷贝、缺页中断、惰性加载页表具体有哪些内容呢??——>虚拟地点、物理地点、读写权限、标志位(对应的代码和数据是否被加载到内存中) 读写权限就可以帮助我们做检查,比方说当前是常量字符区但是你却想修改,就会被/操作体系拦截,该非法请求就不会被发送到物理内存。 标志位就是帮助们判定进程的代码和数据是否被加载到内存中,因为我们知道我们的进程对应的代码和数据是有大概处于挂起状态的(还没加载到内存)。 惰性加载:其实就是需要多少就加载多少。操作体系对大文件是可以实现分批加载,也就是说当前的进程大概只有PCB在内存中,但是代码和数据大概还没立刻加载进来。 缺页中断:在执行进程的时候如果发现标志位表现当前代码和数据没有加载起来,就会发生缺页中断,也就是暂时中断这个进程,然后等代码和数据加载进来之后,再规复原来的状态继承运行。 问题:一次加载进去不是更快吗,为什么需要检测了之后才通过缺页中断加载进去?? ——> 一方面是因为大概这个文件特殊大,以是没办法一次加载进去,就算是可以一次加载进去,可是你用不也是一点点去用么?? 以是缺页中断解决的是初步局部性加载的问题,能够更公道的去利用内存!! 写时拷贝:数据区的数据是按原理是可写的,但是一开始权限会被设置成只读(意思就是当前父子进程共享),一旦父子进程任意一方实验做修改的时候,发现当前的数据是只读的(但是这里不做异常处置惩罚,而是转而发生写时拷贝),然后开辟一块新的物理内存,修改页表的映射 4.2 进程地点空间是如何切换的 进程PCB布局体里有对应的进程地点空间指针,以是进程切换就以为这进程空间地点空间被切换,而页表会被存储在CPU的cr3寄存器中,这其实属于进程的上下文信息,在进程切换的时候会被进程带走,背面再规复过来!! 4.3 进程创建的具体过程分析进程被创建的时候,优先加载的是PCB布局体以及内里临应的进程地点空间布局体,然后他的代码和数据大概不会立刻被加载进来。 4.4 再次明白进程具有独立性1、在内核数据布局上是独立的 2、物理内存中加载的代码和数据,只需要再页表上去表现。虚拟地点可以一样,但是通过页表映射不同的物理地点,就可以让父子进程解耦,一旦发生了任何异常,你释放你的我释放我的。 3、通过页表的虚拟地点映射物理地点,可以任意取地点,甚至是乱序。但是虚拟地点可以将一个线性的地点出现给进程。 五、为什么要有进程地点空间?(重点)以是我们可以对进程举行一个再总结: 讲个故事1: 一个大富翁(操作体系)有10亿美金,而他有四个私生子,但是四个私生子(进程)都并不知道对方的存在,以是他们都以为大富翁只有他唯逐一个儿子,而大富翁告诉他们一旦本身去世了,就把全部的财产留给他,以是每个儿子也都信了,以是大富翁其实给每个私生子都画了一个大饼(进程地点空间)。每个人都以为本身有十亿财产。 但现实上是这些私生子要多少才会给多少(进程需要多少空间操作体系就给多少空间) 结论1:让进程以统一的视角看待内存 如许我进程就不需要关心说具体应该放在物理内存的什么位置,也不需要关心当前这个物理内存是否会影响别人的数据,这些工作都由操作体系去完成。 故事2: 你过年的时候常常有压岁钱,但是你还小以是你常常会买到一些没有用的东西,于是你的妈妈就让你把钱交给他保管,等你需要买什么的时候,他再把钱给你,好比说当你想要买个一块钱的橡皮时,你妈妈就给了你一块钱,但如果你想花100块钱买个游戏机的时候,你的妈妈就不给你买,以是这个过程其实妈妈的作用就是会阻止你做一些不太适合的事变。 结论2:增加虚拟地点空间,可以让我们访问的时候增加一个转换的过程,在这个转化的过程中我们可以对我们的寻址举行审查,以是一旦异常访问,直接拦截,该请求就不会到达物理内存,从而掩护物理内存 结论3:因为有地点空间和页表的存在,将进程管理模块和内存模块举行解耦合 ! 申请物理内存的哪一块?优先加载可执行程序的哪一部分??又或者页表填写到什么地方??这是有Linux的内存模块去管理的,进程并不需要关心。 结论4:其实变量名在定义的时候就已经被转化成一个个虚拟地点了,而我们之以是有a和&a,本质上是为了区分想获取的是变量的值还是地点。 结论5:从前我们所学习的C内存管理,其实本质上是进程地点空间,而内存管理是由Linux替我们完成的,我们上层语言并不需要关心具体的细节,只需要正常去通过对应的线性地点去利用就行了。 六、下令行参数和环境变量在栈的上面以是环境变量和下令行参数是在栈之上的一个独立空间。 以是为什么子进程可以继承父进程的环境变量,因为子进程启动时,父进程已经把对应的环境变量信息加载进去了, 他也是地点空间的一部分,以是他必然有页表去帮助我们建立虚拟地点和物理地点的映射,而当子进程创建的时候,子进程也会将父进程虚拟地点空间当中的环境变量的相关参数也给我们建立了一份映射,以是即使你传参数,子进程也还是能够得到父进程的环境变量信息。 我们如今所关注的是用户空间。 总结以上为个人经验,盼望能给大家一个参考,也盼望大家多多支持脚本之家。 来源:https://www.jb51.net/server/328318fdy.htm 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
|手机版|小黑屋|梦想之都-俊月星空
( 粤ICP备18056059号 )|网站地图
GMT+8, 2025-7-1 18:51 , Processed in 0.039291 second(s), 18 queries .
Powered by Mxzdjyxk! X3.5
© 2001-2025 Discuz! Team.