内存管理之分段与分页

内存管理之分段与分页

转载自多名技术分享者,仅供参考!


第一篇

要理解分段和分页,那么得理解为什么会出现分段和分页的技术。

首先,这两个技术都是为了利用和管理好计算机的资源–内存

在分段这个技术还没有出现之前,程序运行是需要从内存中分配出足够多的连续的内存,然后把整个程序装载进去。举个例子,某个程序大小是10M,然后,就需要有连续的10M内存空间才能把这个程序装载到内存里面。如果无法找到连续的10M内存,就无法把这个程序装载进内存里面,程序也就无法得到运行。

上面这种直接把整个程序装载进内存的方式是有一定的问题的。例如:

1、地址空间不隔离

如何理解地址空间不隔离?

举个例子,假设我有两个程序,一个是程序A,一个是程序B。程序A在内存中的地址假设是0x000000000x00000099,程序B在内存中的地址**假设**是0x00000100x00000199。那么假设你在程序A中,本来想操作地址0x00000050,不小心手残操作了地址0x00000150,那么,不好的事情或许会发生。你影响了程序A也就罢了,你把程序B也搞了一顿。

2、程序运行时候的地址不确定

如何理解程序运行时候的地址不确定?

因为我们程序每次要运行的时候,都是需要装载到内存中的,假设你在程序中写死了要操作某个地址的内存,例如你要地址0x00000010。但是问题来了,你能够保证你操作的地址0x00000010真的就是你原来想操作的那个位置吗?很可能程序第一次装载进内存的位置是0x000000000x00000099,而程序第二次运行的时候,这个程序装载进内存的位置变成了0x000002000x00000299,而你操作的0x00000010地址压根就不是属于这个程序所占有的内存。

3、内存使用率低下

如何理解内存使用率低下呢?

举个例子,假设你写了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的内存无法利用起来,很浪费对吧。

然后,人们就去寻求一种办法来解决这些问题。

有一句话说的好:计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

(这种思想在现在也用的很广泛,例如很多优秀的中间层:Nginx、Redis等等)

所以,分段这种技术就出现了。

为了实现分段的这个技术,需要引入虚拟地址空间的概念。那么什么是地址空间呢?简单的说就是可以寻址的一片空间。如果这个空间是虚拟的,我们就叫做虚拟地址空间;如果这个空间是真实存在的,我们就叫做物理地址空间。虚拟地址空间是可以任意的大的,因为是虚拟的。而物理地址空间是真实存在的,所以是有限的。

然后,分段这个技术做了一件什么事情呢?

把虚拟地址空间映射到了物理地址空间,并且你写的程序操作的是虚拟地址。假设,程序A的虚拟地址空间是0x00000100~0x00000200。此时,不仅需要一块连续的物理内存来存放程序A,还需要把程序A的虚拟地址空间映射到(转换为)物理地址空间。可能,程序A的虚拟地址空间从0x00000100~0x00000200映射到了物理地址空间0x00000000~0x00000100。

那么分段的技术可以解决什么问题呢?可以解决上面1、2两个问题。

在问题1中,假设程序A的虚拟地址空间是0x000000000x00000099,映射到的物理地址空间是0x000006000x00000699,程序B的虚拟地址空间是0x000001000x00000199,映射到的物理地址空间是0x000003000x00000399。假设你还是手残,在程序A中操作了地址0x00000150,但是英文此时的地址0x00000150是虚拟的,而虚拟化的操作是在操作系统的掌控中的,所以,操作系统有能力判断,这个虚拟地址0x00000150是有问题的,然后阻止后续的操作。所以,体现出了隔离性。(另一种体现隔离性的方式就是,操作同一个虚拟地址,实际上可能操作的是不同的物理地址)

(注意,实际上,很可能程序A和程序B的虚拟地址都是0x00000000~0x00000099。这里的举例只是为了方便理解。)

问题2也很好的解决了。正是因为这种映射,使得程序无需关注物理地址是多少,只要虚拟地址没有改变,那么,程序就不会操作地址不当。

但是问题3仍然没有解决

因为第三个问题是换入换出的问题,这个问题的关键是能不能在换出一个完整的程序之后,把另一个完整的程序换进来。而这种分段机制,映射的是一片连续的物理内存,所以问题3得不到解决。

而问题出在哪呢?就是完整和连续

而分页技术的出现就是为了解决这个问题的。分页这个技术仍然是一种虚拟地址空间到物理地址空间映射的机制。但是,粒度更加的小了。单位不是整个程序,而是某个“页”,一段虚拟地址空间组成的某一页映射到一段物理地址空间组成的某一页。(如何理解这个“页”的概念,这个问题下的其他同学回答过)

分页这个技术,它的虚拟地址空间仍然是连续的,但是,每一页映射后的物理地址就不一定是连续的了。正是因为有了分页的概念,程序的换入换出就可以以页为单位了。那么,为什么就可以只换出某一页呢?实际上,不是为什么可以换出某一页,而是可以换出CPU还用不到的那些程序代码、数据。但是,把这些都换出到磁盘,万一下次CPU就要使用这些代码和数据怎么办?又得把这些代码、数据装载进内存。性能有影响对吧。所以,我们把换入换出的单位变小,变成了“页”。(实际上,这利用了空间局部性)

所以,同学们想想,问题3是不是就解决了呢?

所以,分段和分页的区别在于:粒度


作者:匿名用户

出处:知乎

链接:https://www.zhihu.com/question/50796850/answer/522734117


第二篇

内存的分段和分页管理方式和由此衍生的一堆段页式等都属于内存的不连续分配。什么叫不连续分配?就是把程序分割成一块一块的装入内存,在物理上不用彼此相连,在逻辑上使用段表或者页表将离散分布的这些小块串起来形成逻辑上连续的程序。

在基本的分页概念中,我们把程序分成等长的小块。这些小块叫做“页(Page)”,同样内存也被我们分成了和页面同样大小的”**页框(Frame)“,**一个页可以装到一个页框里。在执行程序的时候我们根据一个页表去查找某个页面在内存的某个页框中,由此完成了逻辑到物理的映射。

分段和分页有很多类似的地方,但是最大的区别在于分页对于用户来说是没什么逻辑意义的,分页是为了完成离散存储,所有的页面大小都一样,对程序员来说这就像碎纸机一样,出来的东西没有完整意义。但是分段不一样,分段不定长,分页由系统完成,分段有时在编译过程中会指定划分,因此可以保留部分逻辑特征,容易实现分段共享。


作者:刚吃饱饭的人民

出处:知乎

链接:https://www.zhihu.com/question/50796850/answer/256353435


第三篇

首先分段和分页都是操作系统发展过程中为了更好的使用内存资源,按照一路发展的过程理解比较好理解操作系统厂商和CPU厂商带来的系列变化

保护模式

为什么要有保护模式

实模式是有很大弊端的,首先,直接操作物理内存,这样的话每次只能运行一个程序,并且不安全;另外,内存最大使用到1M,限制太大。

保护模式下,程序不能直接访问物理地址,程序的虚拟地址需要被转换为物理地址后再去访问,地址转换是由处理器和操作系统协作完成的,处理器在硬件上提供地址转换部件,操作系统提供转换过程中需要的页表。

保护模式的寄存器扩展

除段寄存器外,通用寄存器,指令指针寄存器,标志寄存器等都从16位升到了32位,因为段寄存器保留原来的16位也够用。

模式转换

bits伪指令用于指定处理器的运行模式,这一点是编译器和处理器约定的,操作数大小翻转前缀0x66和寻址方式反转前缀0x67用于将当前运行模式下的操作数大小和寻址方式转换成另一种模式。

内存寻址
地址转换

内存控制单元(MMU) 通过一种称为分段单元的硬件电路把一个逻辑地址转换成线性地址,接着,通过第二个称为分页单元的硬件电路把线性地址转换成物理地址。

graph LR
逻辑地址-->线性地址-->物理地址
全局描述符表

最初的操作系统是无法对内存段做访问限制,有了这样的需求以后,CPU厂商决定采用段描述符来实现相关的功能,在硬件一级上添加GDTR和LDTR来支持全局描述符表和局部描述符表,并由硬件负责周边的安全检测。当初的CPU厂商也并不是凭空制造出了这样一个概念,是与操作系统厂商共同协商后才有了一套硬件方面的支持。

如今x86架构的OS,大都都把分段视为是兼容性的考虑(类似于对实模式的处理),在系统初始化阶段象征性地初始化GDT,之后的运行就没分段啥事儿了。地址空间的保护模型都来自分页,像ARM体系结构就不支持分段,仅靠MMU进行保护。

imgimg

内存分页
为什么要分页

分段的内存碎片太大,是计算中发展过程中尝试过的方案,现在的方案是内存分页,通过某种方式,将虚拟地址映射到物理地址,映射的关系是通过一张表实现的,也就是页表。

imgimg

分页机制

分页机制的思想是:通过映射,可以使连续的线性地址与物理地址相关联,逻辑上连续的线性地址对应的物理地址可以不连续。 分页的作用 - 将线性地址转换为物理地址 - 用大小相同的页替换大小不同的段

imgimg

一级页表

我们把一页的大小定义为4K,那么4G就有1M个页,在32位的保护模式下,地址都是32位二进制表示的,用20位二进制定位页表,剩余的12位表示4K里面的偏移。

分页机制打开前要将页表地址加载到控制寄存器CR3中,这个过程是打开页表之前,所以存储的是物理实际地址,每个页表项对应一个物理页,通过页表项就可以访问到实际的物理地址。由于这个过程是固定的,CPU中集成了这个硬件模块,即MMU中的页部件。

imgimg

二级页表
为什么要二级页表

每个进程1M个页表,每个4字节,进程多了占用的内存还是很多的。

一般进程使用的内存是远低于全部虚拟内存的。二级模式只为进程实际使用的那些虚拟内存区分配页表,既提升了效率,也减少了内存的使用量。

imgimg

页目录项结构

imgimg

页表项结构

imgimg

REF
  • 深入理解Linux内核
  • x86保护模式

作者:长安

出处:知乎

链接:https://www.zhihu.com/question/50796850/answer/654281605


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值