网站规划与建设 第2版ppt网站如何在手机端做适配
- 作者: 五速梦信息网
- 时间: 2026年04月20日 07:55
当前位置: 首页 > news >正文
网站规划与建设 第2版ppt,网站如何在手机端做适配,杭州建设网 工程信息网站,电商平台怎么开发Linux下的进程地址空间程序地址空间回顾从代码结果推结论引入进程地址空间页表为什么要有进程地址空间重新理解进程地址空间程序地址空间回顾 我们在初学C/C的时候#xff0c;我们会经常看见老师们画这样的内存布局图#xff1a; 可是这真的是内存吗#xff1f; 如果不是它… Linux下的进程地址空间程序地址空间回顾从代码结果推结论引入进程地址空间页表为什么要有进程地址空间重新理解进程地址空间程序地址空间回顾 我们在初学C/C的时候我们会经常看见老师们画这样的内存布局图 可是这真的是内存吗 如果不是它内存那它是什么呢 从代码结果推结论 在回答上面的问题之前我们先看一段代码 运行结果 通过运行结果我们可以看出父进程的g_val一直都是保持为10但是子进程的g_val却是一直在变化这还不是最恐怖的最恐怖的是父子进程的g_val是一样的地址那么说明父子进程的g_val是同一块空间啊那么是同一块空间的话子进程去修改了g_val父进程再去读取g_val应该是子进程修改过后的可是父进程似乎还是读取的以前的值(10) 首先一块空间是不可能保存两份值的父子进程能从统一个变量里读取两份值出来那么说明父子进程的g_val绝对不是表示的同一块空间g_val出来的地址也绝对不可能是真实的物理地址 如果g_val出来的是物理地址的话那么父子进程的g_val就表示的同一块空间那么从同一块空间读取出来的值就应该是一样的但是事实却不是这样的 那么就说明我们在语言级别上的取地址取出来的绝对不是真实的物理地址相对的我们把这种地址叫做虚拟地址 引入进程地址空间 通过上面的例子我们知道了我们在语言层面上取出来的地址绝对不是真实的物理地址这个我们知道了可是这与我们的进程地址空间有什么关系 在讲解进程地址空间之前我们先讲一个故事 在遥远的美国有一个大富豪这个大富豪有100亿美金同时他有4个私生子A、B、C、D这4个私生子都不知道彼此的存在都认为自己是大富豪唯一的孩子 有一天呢大富豪对分别A、B、C、D单独说你好好干以后我的这100亿家产都是你的用我们现在的话说大富豪的承诺相当于在给A、B、C、D画饼A、B、C、D都认为自己拥有100亿美金因为他们都认为自己是大富豪的唯一继承人在某一天A对大富豪说“爹给我1000美金我需要买个表”大富豪说没问题大富豪就从100亿美金中拿出了1000美金给了AB这时候也想大富豪申请了900美金大富豪毫不犹豫的就答应了但是C对大富豪说“爹快给我50亿美金我这出了点事需要摆一下”大富豪说“滚”大富豪无情的拒绝了C的请求但是C还是认为自己拥有100亿美金因为它认为自己是大富豪的唯一继承人等到大富豪驾鹤西去之时就是100亿美金到账之日 在上面的故事中呢A、B、C、D相当于我们的进程 大富豪给A、B、C、D画的“饼”就是进程地址空间 100亿美金就是物理内存 大富豪就是OS 其中A、B、C、D向大富豪借钱的动作就是向OS申请物理内存申请的太多OS是会拒绝我们的 OS最为我们计算机中的管理者那么它要不要把给进程们画的“饼”管理起来呢 答案是要的为什么呢如果不管理起来的画在进程多起来的时候OS也不知到他给进程们到底画的什么饼 那么如何管理这些“饼”呢 先描述再组织 在Linux中OS利用了一个struct mm_struct{}的结构体将这个饼管理了起来每个进程都有属于自己的专属大饼其中进程的pcb是中具有指向该大饼的指针OS呢会将这些大饼做一个区域划分比如规定大饼的这个区域是干嘛的那个区域是干嘛的这些区域也就是我们看到的什么堆区、栈区、代码区等等这个大饼也就是我们老师在日常中讲解的C/C内存布局 Linux下的mm_struct 结构体就是专门记录这张大饼的 struct mm_struct{ long Code_start; long Code_end; long init_start; long init_end; …… long stack_start; long stack_end; }当我们向堆区申请空间时heap_end就会变大free时heap_end就会变小 说白了进程地址空间就是OS欺骗进程的一种手段让内存误以为自己拥有全部的物理内存 页表 可是进程地址空间毕竟只是逻辑上的内存并不是真正的物理内存是不能存储数据进程的数据和代码是只能存储在物理内存上的但是进程使用的是虚拟内存进程也只能访问虚拟地址但是实际的数据是存储在物理内存上的那么进程是如何通过虚拟地址拿到数据和代码的 实际上在虚拟地址与物理地址之间是有一种映射关系的这种映射关系被存储在页表中每个进程都有自己的页表 当进程需要访问虚拟地址上某一处的数据时OS就会拿着进程提供的虚拟地址根据该进程提供的页表转换成对于的物理地址然后去对于的物理内存上取数据在交给进程这个过程进程是看不到的站在进程的角度就是我进程需要访问虚拟地址为0x11223344处的数据然后就直接拿到了数据在进程看来它就认为自己的数据是存储在虚拟内存上的只要自己需要随时都可以拿到殊不知其真实数据是存储在物理内存上的进程之所以能随时拿到数据都是由OS完成的我们来画个图来理解 只要理解了这一层我们就能回答开头的问题了 老师们经常给我们讲的内存分布实际上并不是真实物理内存的内存的分布而是OS给进程画的一张“大饼”就是让进程认为自己一个就拥有整个内存说白了进程空间就是OS欺骗进程的一种手段 每个进程都有属于自己的一张进程地址空间和对应的页表 回答了开头的问题我们再来解释一下上面代码表现出的情况父子进程对于g_val取地址取出的地址是一样的但是父子进程从g_val取出来的值却不一样 首先父进程会有自己的pcb、进程空间地址、页表那么子进程也会拥有这些东西但是子进程作为父进程的儿子它会继承父进程的大部分属性包括进程空间地址、页表等画图表示就是 那么根据上面图的表示的话父子进程的g_val不就是同一块空间嘛取出来的值也应该是一样的可是为什么父子进程g_val取出来不同的值 我们需要记得进程之间是具有独立性的包括父子进程之间也是如此当我们的子进程在尝试对g_val变量的值进行修改时为了不影响父进程的正常读取g_valOS会启动写时拷贝技术当父子进程中的某个进程需要对父子进程共享的同一块空间进行修改时OS会在物理内存重新开辟一块一摸一样大的空间然后再将数据拷贝过来修改需要修改数据的进程的页表映射关系此时需要修改数据的进程就可以随意的修改了同时不会影响另一个进程的数据保持了进程之间的独立性 画个图来表示 这也就解释了为什么父子进程的g_val是同一个地址但是却存着不同的值 地址相同的原因就是g_val都处于父子进程的进程地址空间的同一个位置(这里说的“处于”并不是真实的存储而是逻辑上的存储)取地址取出来的地址当然一样但是由于子进程的g_val造成了写实拷贝就导致了父子进程的g_val映射到不同的物理地址空间取出来的值自然不一样 写时拷贝是发生在物理内存对于虚拟内存没有影响 注意:我们平时地址取出来的全是虚拟地址(也就是进程地址空间中的地址)我们用户没办法取到真实的物理地址毕竟谁叫我们的进程被OS欺骗了痴痴的认为自己享有全部内存 明白了上面的例子那么我们也就能很好的明白了使用fork函数时利用变量接受fork返回值时明明是同一个变量(虚拟地址相同),但是再父子进程中却输出了不同的值 主要是应为再fork函数的内部也就是return的前一步的时候子进程就已经被创建出来了此时对于接受fork返回值的变量在父子进程中也还是映射的同一块物理空间但是当return的时候就会向这个接受返回值的变量中写入数据此时就会触发写时拷贝那么这时候父子进程中的某个进程就会为自己的这个接受fork返回值的变量重新映射一块新的物理空间这也就是fork函数能返回两个返回值的秘密实际上并不是真的能返回两个返回值只是父子进程中的接受返回值的变量已经是两块独立的物理空间了不在是同一块在虚拟内存上他们也许是同一块但是真实情况并不是 同时页表也不止是会映射虚拟地址的物理地址页表同时也会记录一下映射的物理地址的读写权限 比如 这也是为什么我们平常所说的代码区的数据只能读不可修改的原因 因为当我们进程试图修改代码区的数据时OS会拿着进程提供的虚拟地址代码区的地址然后根据页表映射到对应的物理内存上去但是OS这时候发现这次映射的物理空间在页表中的权限也就只有可读不可修改我们的操作属于权限放大了OS会直接拒绝我们的请求并不是这块空间物理内存本身就只是可读的而是我们通过一些手段从逻辑上限制了这块空间物理内存的权限 为什么要有进程地址空间 上面我们大概讲解了什么是进程地址空间和怎么使用进程地址空间但是为什么要有这个东西呢 1、防止地址随意访问保护我们进程的安全和独立 假设我们不使用虚拟内存就直接使用物理内存 我们现在在物理内存中加载了两个程序现在A程序是我们写的但是我们的代码能力有问题我们的A程序有bug当我们cpu在处理进程A的时候会从进程中读取到不属于进程A的地址也就是说A进程存在野指针问题但是刚好这个野指针被OS分配给了进程B使用 要是这时候我们的进程A有个对该野指针解引用并修改数据的操作的话那就完了因为这就造成了我们明明实在运行进程A但是由于野指针的问题间接的将B进程的数据修改了如果进程B是个银行的账户信息的话那么后果就会很严重这也就破坏了进程之间的独立性同时也对进程的安全运行造成了威胁但是我们使用虚拟内存时我们如果造成了越界访问OS会在映射该虚拟地址的时候检测出来从而拒绝我们的访问这也就让我们无法随意的根据地址访问其他空间了同时进程的独立性和安全性也就增加了 2、进程管理与内存管理解耦合了 再此之前我们先来谈谈malloc的本质 请问只要是我们已使用malloc或new申请空间OS就会立即给我们吗 答案显然不是OS作为整个计算机最基础的软件也是整个计算机中的管理者它是不允许发生任何不高效和浪费的操作的 如果有那么一定是OS的bug 如果OS在我们申请的时候就把空间给我们了那么我们能保证我们申请了就一定使用吗我们一定写过这样的代码在程序的开头就先申请了一段空间但是我们可能写了几十行代码才开始使用这块空间那么在你从申请空间开始到你真正使用这块空间之间这块空间就一直被我们占着其他进程也用不到实属有点“站着茅坑不拉屎”的感觉你说一个进程这样OS还能理解但是如果每个进程都像这样了这就会严重的造成内存资源使用不充分、不高效 如果在我们并未真正使用这段空间的时间段内OS将这块空间拿去给需要的进程使用当我们真正需要使用这块空间的时候OS再给我们这样的话内存使用率不就起来了 那也有人会说我们申请了立马使用就好了嘛对不起在你刚好申请完这块空间的时候CPU处理你的时间到了该换下一个进程被CPU处理了在你等待下一次CPU处理的时候你又是单独站在这块空间自己不用其他进程也用不了又会造成内存资源的浪费OS也不会允许 为此在我们向OS申请空间的时候OS不会立马给我们而是当我们真正需要的时候才会给我们 我们平常使用的malloc、new就是这样的原理malloc、new是在虚拟内存上开辟空间也就是逻辑上开辟的空间返回的指针也自然是虚拟指针虽然我们有了空间但这些空间毕竟是逻辑上的并不能真实的存储数据也就是说这些虚拟空间还没有在页表中建立起与物理内存的映射关系进程现在拿到的只是一张空头支票具体的兑换还是得靠OS只有当我们真正需要使用这块空间的时候OS才会将我们申请的虚拟空间映射到对应的物理内存也就是为我们的虚拟空间在页表中建立起物理地址只有完成映射关系我们进程才能算是真正的拥有自己的空间物理空间 同时我们进程也不必关心OS到底给我们映射的那块空间在物理内存中是否连续等OS可以在物理内存的任何位置映射空间物理内存并不一定是连续的但是我们在虚拟内存上申请的空间一定是连续的 我们作为进程是不关心我们的数据到底存储在物理内存的那一块空间的、申请的物理空间是否连续等等在进程看来进程空间地址就是它的“内存”只要在进程空间地址上连续就行了至于映射到物理内存上是什么情况我们进程压根不关心 为此我们把就把内存管理与进程管理分开了内存管理就处理内存的事进程管理就专门管理进程两个管理之间互不干扰 如果没有进程空间地址的话我们的进程在申请空间的时候OS就会立马给它这样导致内存资源浪费不说OS会需要去刻意寻找一块物理内存这时候就造成进程管理与内存管理耦合也就是说我们我们在进行进程管理的时候就必须借助内存管理的力量这是我们不希望看到的我们希望进程管理能够单独完成自己的事情内存管理也能单独完成自己的事情两个进程耦合度不要太高保证我们内存管理崩溃的时候不影响进程管理进程管理崩溃的时候不影响内存管理 有了进程地址空间我们在申请空间的时候就只启用进程管理先申请虚拟内存当我们真正需要的时候再启动内存管理来为我们分配物理空间这样的话就算内存管理崩溃掉了也不影响进程管理 3、让进程以统一的视角看待内存 虚拟内存是OS欺骗进程的一种手段进程在看待进程的时候都认为自己拥有整块内存然后开始对着“这块内存”开始布局自己的代码和数据但是实际上这些代码和数据到底存没存储起来还得看OS但是站在进程的角度他是认为我们已经布局完整个内存了进程是看不到真实物理内存的进程只能看到进程地址空间 4、可以充分的利用内存资源让内存的利用率变的高效起来 比如两个进程可能都需要访问某个动态库如果没有进程地址空间的话OS就会将这个动态库加载内存两次也就是内存中会有两份一模一样的数据这是没必要的但是有了进程地址空间过后我们可以让两个进程的虚拟地址同时映射到这同一份数据也就是说两个进程可以共享这份数据这份数据也就只需要在内存中存在一份就行了但是在进程看来他们都认为这份数据是自己独享的 重新理解进程地址空间 请问我们的程序在编译完毕但是还没有加载进内存的时候我们的程序内部是否有地址呢 答案是当然有的 我们可以来看看一段代码的汇编文件 我们将这段程序先编译成可执行程序然后利用命令objdump -S对其进行反汇编: 我们会发现在我们的程序在未加载进内存的时候编译器就已经确定好了各条指令的地址这是为什么 答进程地址空间不止是欺骗进程的也会连同编译器也一起欺骗当然这都是非常不标准的描述严格意义上来说源代码在被编译的时候就已经按照虚拟地址空间的方式对代码和数据进行了地址的编制只不过只些代码和数据的地址都是虚拟地址并不是真实的物理地址 只有当我们的程序被加载进内存了才会真正的拥有物理地址 现在我们来理一理整个程序的运行过程 1、将我们的程序加载进内存注意并不是一次性全部加载进去而是先加载一些比较重要的代码和数据 2、OS为该程序建立pcb来管理该进程 3、OS为该进程创建地址空间地址和页表 4、cpu从特定的进程空间地址处读取数据然后OS在根据cpu提供的虚拟地址映射到对应物理地址获取对应的数据给cpucpu开始处理如果OS在根据cpu提供虚拟地址没有建立起对应的物理地址时OS会暂停cpu对于该进程的处理然后重新加载一部分数据进入内存然后再建立映射关系出现这种情况叫做缺页中断 我们画个图来理解 注意在CPU上读取到的地址全是进程空间上的地址也就是虚拟地址CPU也不会直接去物理内存上读取数据
- 上一篇: 网站规划有前途吗兰坪建设公司网站
- 下一篇: 网站规划与开发实训室建设公司宣传片如何制作
相关文章
-
网站规划有前途吗兰坪建设公司网站
网站规划有前途吗兰坪建设公司网站
- 技术栈
- 2026年04月20日
-
网站规划有哪些内容成都微网站公司
网站规划有哪些内容成都微网站公司
- 技术栈
- 2026年04月20日
-
网站规划文字说明帝国网站的互动专栏怎么做
网站规划文字说明帝国网站的互动专栏怎么做
- 技术栈
- 2026年04月20日
-
网站规划与开发实训室建设公司宣传片如何制作
网站规划与开发实训室建设公司宣传片如何制作
- 技术栈
- 2026年04月20日
-
网站规划主要内容大连谷歌seo公司
网站规划主要内容大连谷歌seo公司
- 技术栈
- 2026年04月20日
-
网站过场动画成都网站建设冠辰
网站过场动画成都网站建设冠辰
- 技术栈
- 2026年04月20日
