文章目录

  • ​​1.为什么要有逻辑地址?​​
  • ​​2.逻辑地址如何与物理地址映射?​​
  • ​​3.分页中的时间与空间的优化​​
  • ​​4.程序内部的内存管理——分段​​
  • ​​5.CPU的缓存cache如何起作用?​​

1.为什么要有逻辑地址?

  • 逻辑地址:是直接在程序中看到的内存地址
  • 逻辑内存也叫虚拟内存
  • 硬件可用的地址是变化的, 比如增加减少内存条,程序的地址是写死的
  • 因为程序无法知道可用的逻辑地址,所以必须要作出映射

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

  • 一种简单的思路:固定偏移量映射,eg如下图
    缺点:
    (1)以程序1为例,一个程序所使用的内存是无法计算的,右边程序没有使用的物理内存称之为内碎片
    (2)程序1运行完毕后,释放内存,接着运行程序3,因为程序3的地址是0-201,它无法使用0-200的地址,长期以往,该块内存一直被闲置,,那么这块内存称之为外碎片

操作系统的内存管理_逻辑地址

  • 所以将逻辑内存分为页
    (1)页表:左边代表逻辑内存中的页,右边代表物理内存中的帧
    页表还存储的信息:当前条目是否可用,当前页的读写权限,当前帧是否是脏的等;
  • 操作系统的内存管理_页表_02

  • 每个进程都有自己的页表
    每个进程的帧号不一样,就保证了不同进程之间是隔离的
  • 操作系统的内存管理_页表_03

  • 小知识
    (1)内存的一个地址里面住的是一个字节Byte的数据;
    (2)32位的OS物理地址有2^32个,因而只能使用4GB的内存
    (3)任何一个32位的程序可操作的逻辑地址是2^32个,即4GB;(每个32位的程序都天真的以为自己拥有4GB的内存)
    (4)上面势必会造成多个程序使用内存总和大于物理内存,此时会借助磁盘,将并不着急使用的内存先存到磁盘,PT对应的帧号只显示磁盘
    如下图,大部门页映射到帧中,小部门页映射到磁盘中
  • 操作系统的内存管理_页表_04

  • 内存映射的过程
    eg问题:
    机器:32bit,256MB内存,页大小为4KB
    程序:32bit程序
    逻辑地址0x000011a3如何映射到物理地址?
    分析:
    (1)4K=12bit,就是2^12,所以偏移量是12bit,所以,页号就是32-12=20bit;
    逻辑地址32bit=20bit页号+12bit偏移
    (2)256MB=28bit,就是2^28,偏移量是12bit,所以帧号就是28-12=16bit
    物理地址28bit=16bit帧号+12bit偏移
    对于0x0000011a3而言,1a3代表12bit的偏移地址,000001代表20bit的页号
  • 操作系统的内存管理_逻辑地址_05

  • (3)在页表PT(Page Table)中查找,00001对应的帧号是00f3(16bit转16进制数),在帧内寻找偏移量1a3的地址,最终找到内存;
    如果对应的帧号是磁盘,会发生什么?
    会发生缺页中断或缺页异常,会触发程序进入内核态,内核会到磁盘中找到对应的数据,然后会将其加载到物理内存的帧中,然后把加载好的帧号填写到PT表的帧号那一栏中,重新进行寻址。
    若帧已经加载满了,会有页替换算法(只需知道能选出要逐出的页帧就行了),将最少使用的帧逐出到磁盘(所以linux下的该部分又称之为:swapping),把当前的数据放入到物理的帧中。
    如下图是:逻辑地址映射到物理地址的过程
  • 操作系统的内存管理_分页_06

  • 分页小结
    (1)分页使得每个程序都有很大的逻辑地址空间,通过映射磁盘和高效的置换算法,使得内存“无限大”
    (2)分页使不同的进程的内存隔离,保证了安全
    (3)分页降低了内存碎片问题
    (4)但是上述分页过程中,需要两次(第一次是从页表中获取帧号,第二次:拿着帧号到内存中再查一遍)读内存时间上有待优化,页表占用空间较大,空间上也有待优化

3.分页中的时间与空间的优化

  • 时间优化:
    (1)将最常访问的几个(一般是8-128个左右)页表项存到访问速度更快的硬件中,一般是MMU内存管理单元(一般情况,MMU属于CPU),该页表的名称是TLB(Translation Lookaside Buffer),可以称其为快表;
    (2)先寻址先查TLB,然后miss后,再查PT。
    快表命中率很高,因为一个事实:程序最常访问的页没几个
  • 空间优化:
    多级页表可以缩小页表占用的空间

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

  • 堆区,栈区就是段,段错误啥的。。。
  • 现在我们所说的段,已经不再是最初的会影响内存管理的段了,而是更多的是程序层面的逻辑上的段
  • eg:如图C语言的分段情况:对虚拟地址分的段
    (1)最高的地址空间是留给Kernel Space内核的
    (2)Text段:存储程序本身的二进制字节码;
    Data段:存储程序中的静态的变量
    Heap段:是从低往高增长的
    Stact栈区:是从高往低增长的
    Libraries:是函数库的区域,eg:linux的so文件,windows的dll动态链接库。进程之间是可以共享函数库的,就是进程间通信的共享内存的通信方式。
    补充:(3)malloc若申请>128K的内存,会调用mmap,在堆和栈之间区域申请内存码。和这里的lib区其实是相同的位置的,因为他们都是页映射磁盘。 (mmap就是文件映射内存的系统调用)。
  • 操作系统的内存管理_分页_07

  • 共享内存极其常见,eg:windows下选择文件的那个对话框
  • 操作系统的内存管理_逻辑地址_08

  • 分段和分页的关系
    (1)分段和分页结合的方式是:
    每个段有很多页,页表中存储端号和页号唯一映射物理帧号
    (2)但是段页结合的模式只在x86 Intel cpu等少数上还支持,更新的x86-64架构都不再支持段页结合了。
    但是仍然保留了段的概念,只是程序层面便于计算,并不会影响分页式内存管理
  • eg:两个程序分别映射到物理内存中
    (1)内核区域是各个程序所共享的,所有2个程序都映射到了Kernel内核区域
    (2)各自有各自的栈区,Libraries库区可能是多个进程所共享的
  • 操作系统的内存管理_逻辑地址_09

5.CPU的缓存cache如何起作用?

  • 计算机的存储器结构大致是: CPU寄存器 —缓存cache–存储器(内存)–磁盘存储(硬盘)。从左到又速度从快变慢,存储大小由小变大。
  • 以cache做的事情是把内存里面常用的存储数据存在自己这里供CPU读取,因为cache的访问延迟远远小于内存, 所以访问这部分存在cache里的数据就会比直接去访问内存快的多,大概快一个量级。
  • 至于为什么不用CPU直接读取,第一CPU的寄存器容量非常小,是Kb级别的,你让他去访问,内存,一次就这点,得多久才能把一个QQ那么大的程序运行了。第二是CPU访问内存,速度瓶颈自然在内存这里,那CPU当然访问cache更快了,而且现在的cache分L1 L2 L3这几层,从左到又速度从快变慢,存储大小由小变大。

参考:

https://www.bilibili.com/video/av85489309
https://www.zhihu.com/question/22431522