分段与分页
作者:互联网
分段与分页
一、分页、分段的技术出现之前
-
在分段这个技术还没有出现之前,程序运行是需要从内存中分配出足够多的连续的内存,然后把整个程序装载进去
-
如下图所示,某个程序大小是10M,然后,就需要有连续的10M内存空间才能把这个程序装载到内存里面。如果无法找到连续的10M内存,就无法把这个程序装载进内存里面,程序也就无法得到运行
直接把整个程序装载进内存的方式是有一定的问题的
①地址空间不隔离:举个例子,假设我有两个程序,一个是程序A,一个是程序B。程序A在内存中的地址假设是0x00000000~0x00000099,程序B在内存中的地址假设是0x00000100~x00000199。那么假设你在程序A中,本来想操作地址0x00000050,不小心手残操作了地址0x00000150,那么,不好的事情或许会发生。你影响了程序A也就罢了,你把程序B也搞了一顿。
②程序运行时候的地址不确定:因为我们程序每次要运行的时候,都是需要装载到内存中的,假设你在程序中写死了要操作某个地址的内存,例如你要地址0x00000010。但是问题来了,你能够保证你操作的地址0x00000010真的就是你原来想操作的那个位置吗?很可能程序第一次装载进内存的位置是0x00000000~0x00000099,而程序第二次运行的时候,这个程序装载进内存的位置变成了0x00000200~0x00000299,而你操作的0x00000010地址压根就不是属于这个程序所占有的内存
③内存使用率低下:
- 举个例子,假设你写了3个程序,其中程序A大小为10M,程序B为70M,程序C的大小为30M,但是你的计算机的内存总共有100M
- 这三个程序加起来有110M,显然这三个程序是无法同时存在于内存中的
- 并且最多只能够同时运行两个程序。可能是这样的,程序A占有的内存空间是0x00000000~0x00000009,程序B占有的内存空间是0x00000010~0x00000079。假设这个时候程序C要运行该怎么做?可以把其中的一个程序换出到磁盘上,然后再把程序C装载到内存中。假设是把程序A换出,那么程序C还是无法装载进内存中,因为内存中空闲的连续区域有两块,一块是原来程序A占有的那10M,还有就是从0x00000080~0x00000099这20M,所以,30M的程序C无法装载进内存中。那么,唯一的办法就是把程序B换出,保留程序A,但是,此时会有60M的内存无法利用起来,很浪费对吧
-
对于上面的种种问题,分段的技术就出现了。为了实现分段的技术,需要引入虚拟地址空间的概念(见下)
二、分段技术的出现与虚拟地址空间
-
分段:就是将一个程序分成代码段,数据段,堆栈段什么的,每个段各自管理不同的数据
虚拟地址空间
-
为了实现分段的这个技术,需要引入虚拟地址空间的概念
-
从上面的图片可以看出,程序被分成段之后,其在程序中操作的地址就是段地址(虚拟地址)
-
简单的说就是可以寻址的一片空间。如果这个空间是虚拟的,我们就叫做虚拟地址空间;如果这个空间是真实存在的,我们就叫做物理地址空间。虚拟地址空间是可以任意的大的,因为是虚拟的。而物理地址空间是真实存在的,所以是有限的
虚拟地址空间到物理地址空间的映射
-
分段技术把虚拟地址空间映射到了物理地址空间,并且你写的程序操作的是虚拟地址
-
假设,程序A的虚拟地址空间是0x00000100~0x00000200。此时,不仅需要一块连续的物理内存来存放程序A,还需要把程序A的虚拟地址空间映射到(转换为)物理地址空间。可能,程序A的虚拟地址空间从0x00000100~0x00000200映射到了物理地址空间0x00000000~0x00000100
分段技术解决了上面的问题①和问题②
-
分段技术解决了问题①:
-
在问题1中,假设程序A的虚拟地址空间是0x00000000~0x00000099,映射到的物理地址空间是0x00000600~0x00000699,程序B的虚拟地址空间是0x00000100~0x00000199,映射到的物理地址空间是0x00000300~0x00000399。假设你还是手残,在程序A中操作了地址0x00000150,但是因为此时的地址0x00000150是虚拟的,而虚拟化的操作是在操作系统的掌控中的,所以,操作系统有能力判断,这个虚拟地址0x00000150是有问题的,然后阻止后续的操作。所以,体现出了隔离性。(另一种体现隔离性的方式就是,操作同一个虚拟地址,实际上可能操作的是不同的物理地址)
-
(注意,实际上,很可能程序A和程序B的虚拟地址都是0x00000000~0x00000099。这里的举例只是为了方便理解。)
-
-
分段技术解决了问题②:正是因为这种映射,使得程序无需关注物理地址是多少,只要虚拟地址没有改变,那么,程序就不会操作地址不当
-
但是分段还有解决上面的问题③,于是分页技术的出现解决了问题③
三、分页技术的出现
-
分段机制,映射的是一片连续的物理内存,所以问题③得不到解决。问题出在哪呢?就是完整和连续
分页技术的大概原理
-
分页技术的出现就是为了解决上面的问题③的。分页这个技术仍然是一种虚拟地址空间到物理地址空间映射的机制。但是,粒度更加的小了。单位不是整个程序,而是某个“页”,一段虚拟地址空间组成的某一页映射到一段物理地址空间组成的某一页
-
分页这个技术,它的虚拟地址空间仍然是连续的,但是,每一页映射后的物理地址就不一定是连续的了。正是因为有了分页的概念,程序的换入换出就可以以页为单位了。那么,为什么就可以只换出某一页呢?实际上,不是为什么可以换出某一页,而是可以换出CPU还用不到的那些程序代码、数据。但是,把这些都换出到磁盘,万一下次CPU就要使用这些代码和数据怎么办?又得把这些代码、数据装载进内存。性能有影响对吧。所以,我们把换入换出的单位变小,变成了“页”。(实际上,这利用了空间局部性)
图示说明如下图所示:
-
最左侧的是用户程序,程序在逻辑上仍然是分段的(代码段、栈区、堆区等),但是从物理存储的角度来说,整个程序中被分为一页一页来进行存储
-
最右侧的是内存,当用户程序使用分页技术之后,内存也被划分为与程序页面大小相同的块
-
中间是页表,页表的左侧记录的是程序的页号,页表右侧记录的是内存的快号;每一行的页号与块号存在映射关系,也就是说程序的某一页是映射存储在内存的某一块上的。例如下图所示,程序的第0页存储在内存的第2块上,程序的第1页存储在内存的第3块上......以此类推
-
例如,下面是3个程序的映射情况,可以看到不同的程序它的内存被分为不同的页,然后映射存储在内存的不同块中
页面大小的选择(选择性阅读)
-
页面大小是固定的,由你的机器和硬件所决定,不同的机器可能页面大小不同
-
页面大小一般是2的幂,通常是512B~8KB
-
页面大小的区别:
-
页面尺寸小:内存碎片小,内存利用率高(因为页面小,自己琢磨琢磨就好),但页面数目多,使页表过长,占大量内存,管理开销大
-
-
页面尺寸大:页表端,内存利用率低且内存碎片化大(因为页面大,自己琢磨琢磨就好),管理开销小
页面的地址结构(选择性阅读)
上图给出一个页的结构,如下图所示:
-
每个页的结构如下,长度为32位,即每页的大小为4KB
-
0~11位:存储位偏移(页内地址),因此一个页可以表示地址范围为0~2^12
-
12~31位:存储的是页号,地址空间最多允许有1M个页,因此可以有2^20个页面
所以当一个程序去寻址的时候需要3个步骤:
-
第一步:先通过查找段,例如你访问一个局部变量,那么就去程序的栈段中去找
-
第二步:找到了栈这个段之后,再根据你这个变量的地址开始对4KB进行取余操作,求出页号,然后在找到你这个数据所存储的页地址
-
第三步:当找到了指定的页之后,因为地址对4KB取余之后<=4KB,所以再根据取余的结果在指定的页中进行偏移,找到页内偏移地址,最终访问到实际地址
总结起来就是“段号+页号+页内偏移”
-
总结:若给定一个逻辑地址空间中的地址为A,页面大小为L,则有如下的公式
-
页号P=INT[A/L]
-
页内地址d=[A] mod L
所以,分段和分页的区别在于:粒度
-
四、分页、分段的区别
-
页是信息的物理单位,分页是为实现离散分配方式,以消减内存的外零头,提高内存的利用率。段则是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了能更好地满足用户的需要
-
页的大小固定,且由系统决定;而段的长度却不固定,决定于用户所编写的程序
-
分页的地址空间是一维的,程序员只需利用一个记忆符,即可表示一个地址;而分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址
————————————————版权声明:本文为CSDN博主「董哥的黑板报」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_41453285/article/details/107827460
标签:分段,程序,虚拟地址,地址,内存,空间,分页 来源: https://www.cnblogs.com/Samforrest/p/15969217.html