内存管理

1. 为什么要有逻辑地址

单片机是没有操作系统的,所以每次写完代码,都需要借助工具把程序烧录进去,这样程序才能跑起来。

另外,单片机的 CPU 是直接操作内存的「物理地址」。
在这里插入图片描述
在这种情况下,要想在内存中同时运行两个程序是不可能的。如果第一个程序在 2000 的位置写入一个新的值,将会擦掉第二个程序存放在相同位置上的所有内容,所以同时运行两个程序是根本行不通的,这两个程序会立刻崩溃。
这里关键的问题是这两个程序都引用了绝对物理地址,而这正是我们最需要避免的。

我们可以把进程所使用的地址「隔离」开来,即让操作系统为每个进程分配独立的一套「逻辑地址」,人人都有,大家自己玩自己的地址就行,互不干涉。但是有个前提每个进程都不能访问物理地址,至于虚拟地址最终怎么落到物理内存里,对进程来说是透明的,操作系统已经把这些都安排的明明白白了。
在这里插入图片描述

2. 逻辑地址如何与物理地址映射

一种思路是固定偏移量映射。
如下图程序1的偏移量是0,程序2的偏移量是200。如果程序1操作的逻辑地址是100,那个物理地址也是100;如果程序2操作的逻辑地址是50,那个物理地址也是偏移量加上50,也就是物理地址250。
在这里插入图片描述
这样做的缺点会导致内存浪费: 程序运行时内存会动态变化,很难确定边际值。如图中的程序1,即便根据估测最多使用200字节内存,但是平常运行时内存可能100字节都不到,程序利用率较低,这些没有被利用的内存我们称为内碎片

上图中的程序1运行结束后,会释放出0-200的内存,但是新起的程序2需要0-201字节范围的内存,也就是说程序2无法利用程序1结束后释放的内存。如果一直没有程序需要200字节以内的内存,这块内存一直被闲置,那么这段内存我们就称为外碎片
在这里插入图片描述

2.1 分页

为了解决上边的问题,提出了一种分页的思想。分页是将逻辑内存和物理内存按照指定大小进行分隔成很多片,分隔后的每一片的就是页。linux上是4k内存分为一个页。
逻辑页是抽象的,需要映射到物理的页上,才能完成对内存的操作。我们把逻辑页叫页(page)物理页叫帧(page frame)。页号-帧号的映射表叫页表(page table)。
在这里插入图片描述

同时每个进程都有自己的专属页表,如下:
在这里插入图片描述

小知识点:
在这里插入图片描述

为什么32位系统只能使用4GB内存?
CPU(寻址宽度)地址总线宽度为32位,每一个二进制位表示0或1两个数字,一共可以表示多少个数字呢?2^32个。 这代表CPU可以访问232个内存地址,每个地址大小1个字节,总共是232字节,换算下来地址大小是4G.
CPU地址总线表示地址个数,地址的大小是一字节。总个数字节就是总地址大小,也就是内存大小。
https://zhidao.baidu.com/question/454551158501894365.html

在这里插入图片描述
可能会出现映射的帧号是disk,即映射到了磁盘上。此时会触发缺页异常,进入内核态,内核从磁盘中读取缺的这页内容,将其加载到物理内存中。但是物理内存的帧有可能所有帧都满了,此时就需要逐出不太"重要"的帧。
在这里插入图片描述

3. 分页优化

上面提到了逻辑-物理页的映射,这就是页表(简称PT)。但是上面的页表其实除了简单的页号映射,还存储了其他一些属性:是否有效,读写权限,修改位,访问位(淘汰算法和TLB中用),是否是脏(被修改过就是脏的,因为他和硬盘上的数据不一致),是否允许被高速缓存等等。

页表存于主存中,每个进程都有自己的页表。

上面可以看到基于页表的寻址,需要两次访问主存(页表是存在主存的),效率低下。将最常访问的几个(一般8-128个左右)页表项存在访问速度更快的硬件中,一般是在MMU(内存管理单元),这个小表的名称为TLB,可以称为快表
寻址先查TLB然后miss后再查PT。快表命中率很高,因为一个事实:程序最常访问的页没几个。
在这里插入图片描述

4.程序内部的内存管理-分段

严格意义的分段是,每一段的虚拟地址都是从0开始。然后页表是段号+页号来映射帧号的。但是这种形式已经被废弃了,只有x86 32位的intel的cpu还保留了这种段页结合的方式,即严格意义的分段已经用的很少。

那为什么还经常听到段的概念?现在所说的段一般是程序在逻辑层面保留的概念,对逻辑地址有个粗略的划分,便于程序编写,但是并不影响os的内存管理(还是分页管理)。

以32位程序为例,在逻辑空间中最高的0xc0000000 - 0xffffffff这1G的内存是给内核留出的。剩余3G内存从低到高分别是Text、Data、Heap、Lib、Stack。

Heap是从低往高增长,Stack是从高往低增长,且有个最大限制。Data存储静态变量Text存储程序二进制码,Lib存储库函数需要占用的内存,多个程序如果都使用了相同的库,内存是共用的(共享内存)。各个部分的留有随机的一段偏移量,可以保护程序,这也使得每次执行程序的时候变量所在的内存地址总是不同的。
在这里插入图片描述

分段是逻辑空间上的,不影响分页的内存管理方式,后面进行分页,映射到物理内存上各部分跨多个页其实并不连续。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值