688-内存管理和虚拟内存讲解大全

为什么要进行内存管理?

(1)仓库管理
对于仓库来说,如果没有合理地管理,随意的乱堆乱放,大量的空间会因为无法被充分利用而浪费,但如果对仓库空间进行合理的规划和分配,物体移走后也进行及时的回收和零碎空间整理,仓库的存储能力就会被最大化利用。
内存也是一个仓库,只不过内存这个仓库使用来存储各种数据的,仓库需要管理才能被最大化的利用,内存也是一样的道理。

(2)内存管理
(a)内存管理的道理与仓库管理同,也必须要对内存空间进行合理地规划和安排
(b)进程运行时,内存管理会负责为进程分配合理的内存空间,并管理好使用的空间
(c)进程终止后,内存管理会及时回收并整理内存空间。

(3)虚拟内存机制
为了更好的进行内存管理,OS的内存管理会提供一个虚拟内存机制,这个虚拟内存机制是驾在物理内存之上的,实现的是一个内存管理机制,通过这个管理机制合理地管理内存,为每一个进程提供最好的内存空间的管理,因此内存管理
这一小节的重点是介绍 “虚拟内存机制”。
我们在前面也说过,所有的现代操作系统,不管是服务器上的大型操作系统,还是PC、平板、移动设备上的中小型操作系统,都有虚拟内存这个东西,虚拟内存对应现在操作系统来说,是一个非常重要的机制,因此有必要了解虚拟内存机制的实现原理。
  
(2)程序被加载运行
为了介绍清楚为什么需要虚拟内存机制,以及虚拟内存实现的大致原理,暂且不直接讲虚拟内存的内容,我们先从程序的加载运行说起,再来引出“虚拟内存机制”。
所有的操作系统都有内存管理,但是不是所有的系统都有虚拟内存机制,有虚拟内存机制的OS,内存管理基于虚拟内存实现。

裸机程序的加载运行

(没有运行在操作系统上的程序)
(a)编译链接后,得到机器指令程序
(b)程序直接被加载到物理内存上。
(c)cpu执行指令,程序被运行
首先Pc这个寄存器中存放第一条指令在内存中的地址,cpu控制器按照这个地址从对应的内存单元取出指令,CPU执行指令,然后地址+1取出第二条指令,整个程序得以运行,运行起来后的程序就演变为了进程。
图:
在这里插入图片描述
文字编码程序,编译得到机器指令程序,在磁盘上,加载运行的时候,把机器指令程序全部复制到物理内存中,然后CPU通过取物理地址去运行的
直接从磁盘加载到物理内存上
CPU通过三大总线,因为指令在内存中是以电信号的形式存在的,CPU得到这个电信号以后,按照电信号的二进制数据,执行,比如说做加减运算之类的,按指令要求计算,PC地址加1就得到第二条指令的地址,然后通过这个地址去取第二条指令,整个程序就运行起来,当把最后一条指令运行完毕,程序结束

(d)加载运行裸机程序的特点
· 没有OS参与,只运行一个程序,是单进程的
· 物理内存远比程序大,程序的加载都很简单
· 直接使用真实的物理地址(也是电信号)访问内存
· 早期的没有OS的计算机,以及现在的计算机资源较少的单片机还在运行裸机程序
在裸机情况下,由于程序的运行非常的简单,因此根本不需要什么内存管理,也没有OS来体用内存管理的机制。
(e)对于现在常规的计算能力稍强的计算机来说,都需会运行操作系统

DOS系统下的程序加载运行

随着计算机的发展,后来出现了DOS操作系统,有了DOS操作系统后,在一台计算机上就可以同时运行很多个程序(进程)。
在DOS系统下,我们可以将很多个的程序全部都加载到物理内存中,通过快速的时间片切换,cpu轮换着执行不同程序的指令,是的众多进程可以被并发运行。
图:
(命令行界面,不能通过鼠标来操作电脑)
在这里插入图片描述
在这里插入图片描述
把机器指令代码全部复制到物理内存中
从000001物理地址开始,在PC计数器存储,通过三条总线进行获取指令

(a)特点
· 每个程序代码必须要全部加载到物理内存中
· CPU运行某个程序时,还是直接使用物理地址访问物理内存中的程序指令
· 经过OS调度器的调度,通过时间片的切换,CPU轮流着执行不同进程的指令,从而实现进程的并发运行。
CPU通过PC计数器的地址+1,不断获取下一个指令的地址,不断执行下去
(b)DOS下程序加载运行面临的问题
· 问题1:程序变多了后,内存不够用
· 问题2:容易篡改别的程序的内容
  
由于是使用物理地址来访问内存空间的,如果程序员写程序时疏忽了,使用了错误的地址,而该地址恰好是其它程序在内存空间的地址,程序员非常容易把别人空间的数据被容给改写了。
人是非常容易犯错误的,你让程序员小心注意不要乱写,这是解决不了问题,必须要靠一种严密的机制来预防这种错误,只要机制靠谱,就算是程序员把地址写错了,机制会帮你预防这种错误。

(c)向DOS引入内存管理机制———虚拟内存机制
为了预防程序员使用了错误地址修改了别的程序数据的情况,OS中引入了虚拟内存机制,使用这个机制就能有效的预防这样的情况发生。
虚拟内存机制的基本原理就是,在OS加入内存管理的软件管理代码,让这个虚拟内存机制去管理物理内存,从而营造出一个虚拟内存,但有了虚拟内存后就可以解决上述的两个问题:
1· 该机制使用硬盘空间弥补内存的不足,可以运行更多的程序

虚拟内存机制:非常聪明,不是把代码全部复制到物理内存机制中去,只是复制你当前要运行它的那部分代码,剩余的部分还是存放在磁盘中,复制进去的那部分运行完之后,把第二部分放进去运行,以此类推,不会把整个程序代码直接复制进去物理内存,这样就节省空间了!可以运行更多的进程了。(变向的使用硬盘来扩充内存的空间的不足)
2· 虚拟内存提供虚拟地址
Cpu取指令运行时,使用的是虚拟地址,只不过虚拟地址必须转为真实的物理地址才能访问物理内存。
使用程序员编程时因为操作的是虚拟地址,而不是物理地址,就算是你写错了,使用虚拟地址是不会改了别人空间的数据的。
CPU使用的虚拟地址,要进行映射转换成物理地址,去取指令。

至于“虚拟内存”机制是如何实现以上两点的,在下一小节里面会详细介绍。

虚拟内存

(1)虚拟内存的基本原理

(a)原理图
图:
在这里插入图片描述
(b)图形解释
编译链接时
-在编译链接程序时,程序代码会被安排虚拟地址,也就是假地址,说白了就是一些编号,并不代表任何真实的存储空间
-所有程序再被编译时,被安排的虚拟地址都是相同的
-程序员编写程序时,都是使用虚拟地址来操作空间的

·程序加载时
是由操作系统(有一个父进程)来加载的

  • 程序会被分成了很多的部分,每部分的大小一般为4k(4*1024)左右
  • 加载时,仅加载当前要运行某几个部分,因为不会将所有的程序都加载到内存中,节省了内存空间,因此内存中可以加载非常多的程序。
  • 加载后,马上建立一张映射表标记当前部分在内存里面还是在外存上,建立虚拟地址和真实的物理地址间的对应关系(这张表在操作系统中是以代码形式表现的)
    在这里插入图片描述
    -CPU取指运行
    调度器根据调度算法,调度到某个程序(进程)时,CPU才会对其进行取指执行(取指:取出指令)。
    通过虚拟地址取指CPU取指时,使用虚拟地址取指令,此时需要查找映射表,查找发现如果指令所在part在物理内存中,通过地址对应关系,得到part物理内存地址,然后使用这个地址到物理内存找到该指令
    如果part在外存上,通过地址对应关系得到part在外存上的地址,到外存上找到该part并加载到内存替换掉其它part,更新映射表,再将通过地址对应关系,得到内存中的物理地址,到物理内存中取出指令运行
    在这里插入图片描述

·并发运行
当多个进程都被轮流调度,由CPU取指执行,每个进程执行一个自己的ms级时间片,在宏观上就是实现了进程的并发运行。
(c)为什么称为虚拟内存
虚拟内存是对CPU来说的。
CPU被欺骗了,它认为使用这个虚拟地址访问了某个内存,但是这个虚拟地址只是一个编号,这个虚拟地址对应的只是 一个虚拟的内存,实际上程序被分成两部分放在了内存上和外存上。
(d)虚拟内存机制为什么节省了内存
因为只加载了你要运行的那部分,其他的都在外存上,外存帮忙存了其他代码,相当于使用外存扩展了内存空间。
(e)虚拟内存机制为什么能够防止修改别人的程序空间
自己的虚拟地址只映射了自己的物理内存空间和外存空爱,就算是程序员把地址写错了,但是错的也只是虚拟地址,由于虚拟地址只映射了自己的空间,顶多也就把自己的空间给改了,不可能把别人的空间给改了。

(2)虚拟内存机制的具体实现

(a)将内存和程序分页
图:
在这里插入图片描述
高级语言编译后的机器指令程序,加载到磁盘上,磁盘是有地址的,从0开始,往上走,程序在编译之后,会被安排虚拟地址,可以从任何位置开始,反正是虚拟的,比如说,是从4k开始,1k是1024字节,虚拟地址如图中所示。vp1,vp2,,,是虚拟页,因为用的是虚拟地址,所以是虚拟页,所有的程序在被编译器编译后,都会被安排虚拟地址。因为是虚拟地址,所以程序被分为很多的虚拟页。每一页是4k大小。就是前面所述的part。
物理内存也被分成一页一页的,每一页大小是4k,也有地址,物理地址。
因为最后是要把程序加载到物理内存中去运行的,所以物理内存也是要分成一页一页的部分来适合程序的运行。

(b)加载程序,建立映射页表
图:
在这里插入图片描述

加载:把磁盘上的机器指令程序导到物理内存上去运行。只加载立马要运行的指令部分到物理内存上。其他的还留在磁盘上。
操作系统加载磁盘上程序的时候,需要一个进程协作辅助(父进程),把这个程序加载到物理内存上,这个程序就变成进程。那么这个程序运行起来变成进程,操作系统的虚拟内存管理机制会给这个程序创建一个页表。虚拟内存机制是管理机制。
父进程运行的过程中也有页表,加载出子进程,子进程从父进程复制页表,作为新的程序-子进程的页表,然后进行修改,得到新的内容的页表,就是当前进程的页表。

PTE1是虚拟页vp1的页号,PTE2是虚拟页vp2的页号…
是否加载:是否被加载到物理内存上,是就是1,不是就是0
物理内存上的vp1,vp2,vp3是从磁盘上vp1,vp2,vp3加载进去的。
所有在操作系统上运行的进程(程序),都有一张自己的页表,OS的虚拟内存机制就是使用每个进程的页表来管理这些虚拟页的。

(c)CPU通过“虚拟地址”取指并执行进程
图:
在这里插入图片描述
程序加载到物理内存上,程序是一页一页组成的,每一页放的就是指令,CPU取这些指令来执行,加法减法逻辑运算之类的,指挥整个计算机工作。
CPU有PC程序计数器这个东西,放的是当前要执行的指令的地址-虚拟地址,用虚拟地址去取指令的,但是程序是存储在磁盘和物理内存上的,虚拟地址只是个用来帮助管理的假的编号,不能去直接找指令。虚拟地址首先给MMU,MMU(内存管理单元)协助虚拟内存机制管理物理内存和磁盘的映射,虚拟内存就是虚拟地址对应的假内存,MMU得到这个虚拟地址后,就去查页表,用虚拟地址除以4k得到页号,在这里插入图片描述
然后看是否加载这一栏对应的是1还是0,如果是1,就是在网络物理内存,然后看后面的那栏显示的所在物理内存的地址,然后去物理内存取指令给CPU执行,如果是否加载这一栏对应的是0,这页是在磁盘上,操作系统引发缺页异常,因为物理内存缺当前搜索的这页,把当前页对应的磁盘上的指令加载到物理内存上,放在空页上,或者把以前的不活跃的页干掉,然后替换,然后更新映射页表,然后CPU重新取指令,还是使用虚拟地址,除以4k得到页号,然后去页表查,发现是1,在物理内存上,就通过这个物理地址从物理内存取指给CPU执行。
在这里插入图片描述

(d)缺页异常处理
图:
在这里插入图片描述
vp1在物理内存上被覆盖后,把映射页表的1改为0,地址改为在磁盘上的地址。
在这里插入图片描述

动态库的实现

动态库也叫共享库,核心是共享,动态库只能在有OS的计算技术使用,因为动态库的实现需要虚拟内存机制的支持,如果是裸机的话,是没有OS,没有OS就没有虚拟内存机制,在裸机上只能使用静态库。
OS: 动态库和静态库都可以,但是肯定是使用动态库划算
裸机上:只能使用静态库
为什么称为动态库???

静态库是在编译程序时就决定好了的,库代码已经被复制到了程序中,但是动态库不一样,程序使用这个动态库时,并没有将动态库代码复制到程序中,只是在程序中留下了一片空的虚拟地址作为接口,这些虚拟地址并不对应真实的指令。
当我们的程序被加载到内存中运行时,操作系统才会动态的去加载动态库,因为动态库时共享的,因此动态库也被称为共享库。
图:
在这里插入图片描述
CPU拿虚拟地址查页表,找到页号,发现是否加载是1,找到动态库虚拟页对应的物理内存的地址,去物理地址取指给CPU执行
动态库在物理内存中只有一份,但是每个程序都有自己的映射页表,如果有使用到动态库,会映射到同一份动态库的物理地址
动态库使用的内存相当于静态库来说节省非常大的空间!

程序中的动态库接口
程序中使用了动态库的话,编译程序时,会预留一片虚拟地址。
当程序运行起来后,这片虚拟地址会被映射到物理内存上的动态库,建立虚拟地址和动态库物理地址的对应关系。

进程间通信 之 共享内存

(a)进程间通信很困难
每个程序都是用虚拟地址操作的,各自的虚拟地址只映射自己的空间,程序之间没有交集,它们之间很难进行信息共享(通信)。
为了能够通信,设计了很多的通信机制,其中就有共享内存,共享内存的实现原理与动态库的实现原理是一样的。
(b)共享内存的原理
不同进程共享了同一片空间后,一个往里方数据,另一个从里面取数据,就实现了通信。
与共享动态库的区别仅仅是,共享动态库时,共享空间里面放的是动态库的指令,供不同进程共享执行。
而共享内存仅仅只是一片空的共享空间,只是是用来通信用的。
共享里面的代码和指令
两个进程用自己的一片虚拟地址专门去映射同一个物理内存空间。

总结

图:
在这里插入图片描述

多进程是如何共享供一个OS的:
图:
在这里插入图片描述
在安排虚拟地址的时候,还会多安排几个虚拟地址,这片虚拟地址不对应任何应用程序代码,是用来映射操作系统的,当加载程序的时候,会建立一张映射表,这片虚拟地址会映射到操作系统上。映射关系在映射表中。这片虚拟地址和已有的虚拟地址是连在一起的。
调用系统调用函数:
比如说,CPU通过100000这个虚拟地址(应用空间)去访问应用程序指令,虚拟地址最终被映射到物理地址,通过物理地址找到指令,在物理内存的part1取出指令给CPU执行,在执行的过程中,它发现还有调用操作系统提供的函数,这个函数的程序代码指令是放在操作系统这一块上的,它会通过从100000虚拟地址跳转到刚才所述的专门映射操作系统的空的虚拟地址上(内核空间),然后查找映射表,然后访问到操作系统空间所在的物理地址,取指运行,执行的就是系统调用函数的代码了。操作系统的内部代码都和虚拟地址建立了映射关系。(前提是操作系统已经加载到内存上去运行)
在这里插入图片描述

CPU被欺骗后的内存错觉:
图:
在这里插入图片描述

CPU使用虚拟的地址运行每一个进程,CPU被虚拟地址欺骗后,CPU人为每一个进程都有一个自己的内存,这个欺骗CPU假内存,就称为虚拟内存。
CPU认为整个程序(进程)运行在独立的虚拟内存上,因此虚拟内存空间,也被称为进程空间。
应用空间对应的虚拟地址:用于访问应用代码。
内核空间对应的虚拟地址:用于映射到OS上,当应用代码调用OS的系统函数时,就会使用内核空间的虚拟地址去访问OS。映射的是整个操作系统的内核。所有进程共享同一个操作系统。
多个进程调用系统函数不冲突,因为CPU只有1个,运行时不会发生冲突。
使用虚拟地址,不管是访问应用代码,还是访问OS,虚拟地址都需要被转成物理地址,到实际的物理内存中去访问应用代码或者OS的代码。
上面这张图可以简化为:
图:
在这里插入图片描述

虚拟内存就是通过虚拟内存机制,在物理内存和硬盘上,营造出来的一种假象,就像以前有个电影《私人订制》。
C语言程序可能运行在裸机上,也可能运行在虚拟内存上,C语言程序运行在OS上,那么一定是运行在虚拟内存上的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值