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

news/2024/11/29 13:45:05/

为什么要进行内存管理?

(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上,那么一定是运行在虚拟内存上的。


http://www.ppmy.cn/news/541692.html

相关文章

虚拟内存设置(可扩展板载内存)

一、作用和原理 1、原理:在硬盘上划分出一个空间模拟成内存空间来使用,可以使得应用程序认为拥有连续的可用的内存(一个连续完整的地址空间),而实际上,虚拟内存通常是被分隔成多个物理内存碎片&#xff0c…

【Ubuntu16.04 扩大内存空间 设置虚拟内存 史上最详细 】

一、开发环境 开发环境:Ubuntu16.04 二、设置虚拟内存 1、新建内存 新建16G内存 ,一般为真机的两倍 sudo fallocate -l 16G /icedustpan2、查看虚拟内存 ls -lh /icedustpan可以看到一个16G的虚拟内存文件 3、设置虚拟内存权限 sudo chmod 600 /i…

虚拟内存与物理内存与内存碎片-杂谈

内存杂谈 虚拟内存与物理内存 为什么要有虚拟内存??? 1.每个进程有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址(每个进程都假设自己看到的是完整的从0开始的内存) 2.程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存…

虚拟存储器与虚拟内存

1.为什么需要虚拟存储器? 程序在os中能够执行,需要经过,编译-链接-装入 在没有虚拟存储器之前,源程序在gcc –o 后生成的文件是可执行目标程序a.out,每条指令都有一个逻辑地址 32位。它存在硬盘上。 要执行时&#…

虚拟内存管理加拓展(全网最细)

写在前面:我是【程序员宝藏】的宝藏派发员,致力于创作原创干货。我热爱技术、热爱开源与分享,创作的【计算机基础面试问题】系列文章和【计算机基础主干知识】系列文章广受好评!后期会创作更多优质原创系列文章!如果您…

虚拟内存空间

每一个进程都会对应一个虚拟地址空间,32位操作系统会为每个进程分配4G(2的32次方)的虚拟地址空间,而MMU(Memory Management Unit,内存管理单元)负责把这4G虚拟内存映射到实际的物理内存中。这4G…

Virtualbox 扩展虚拟磁盘空间大小

有时我们在使用Virtualbox虚拟机时,分配给虚拟机的磁盘空间太小,导致后期需要扩容,通过以下方法可以扩展磁盘空间。 增强虚拟磁盘空间容量 扩展前最好把所有快照删除掉! 方法一:扩展磁盘空间 打开Virtualbox所在的…

【Linux】Linux权限的概念、Linux权限管理、文件类型和访问权限的设置、粘滞位介绍

文章目录 1.Linux权限的概念2.Linux权限管理2.1文件访问者的分类2.2文件类型的访问权限2.3文件权限值的表示方法2.4文件访问权限的相关设置方法 3.目录的权限4.粘滞位 1.Linux权限的概念 在生活中,一件事情是否允许被一个人做,就是叫做权限,权…