3.0 什么是内存
内存是电脑的一个硬件组成部分。从单片机的组成我们可以看到,CPU、内存和输入输出接口,就组成一个完整的电脑,其他统统属于外设。内存是可以被CPU通过总线进行操作的,也就是与CPU之间有总线相连接的。电脑所有的输入输出,都是要从内存来实现的。内存包括只读内存ROM和读写内存RAM,但在个人电脑(PC)中,我们通常所说的内存,是指读写内存。
3.1 内存管理介绍
操作系统的内存管理主要是做什么?
- 操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存)。
- 另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情。
3.2 操作系统的内存管理机制了解吗?内存管理有哪几种方式?
简单分为连续分配管理方式和非连续分配管理方式这两种。
- 连续分配管理方式是指为一个用户程序分配一个连续的内存空间,常见的如 块式管理 。
- 同样地,非连续分配管理方式允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理 和 段式管理。
块式管理
远古时代的计算机操系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片。
页式管理
把主存分为大小相等且固定的一页一页的形式,页较小,相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
段式管理
页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。 段式管理把主存分为一段段的,段是有实际意义的,每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址。
段页式管理机制
段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。
简单来说:分页可以有效提高内存利用率,分段可以更好满足用户需求。
3.3 快表和多级页表
页表管理机制中有两个很重要的概念:快表和多级页表,这两个东西分别解决了页表管理中很重要的两个问题。
在分页内存管理中,很重要的两点是:
- 虚拟地址到物理地址的转换要快。
- 解决虚拟地址空间大,页表也会很大的问题。
快表
快表,即 TLB( Translation Look-aside Buffer) ,转换表缓冲区。
为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。
- 我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。
- 作为页表的 Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存。
- 有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。
使用快表之后的地址转换流程是这样的:
- 根据虚拟地址中的页号查快表;
- 如果该页在快表中,直接从快表中读取相应的物理地址;
- 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
- 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。
多级页表
引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。
总结
为了提高内存的空间性能,提出了多级页表的概念;但是提到空间性能是以浪费时间性能为基础的,因此为了补充损失的时间性能,提出了快表(即 TLB)的概念。 不论是快表还是多级页表实际上都利用到了程序的局部性原理,局部性原理在后面的虚拟内存这部分会介绍到。
3.4 分页机制和分段机制的共同点和区别
- 共同点:
- 分页机制和分段机制都是为了提高内存利用率,减少内存碎片。
- 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
- 区别:
- 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
- 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
3.5 逻辑(虚拟)地址和物理地址
我们编程一般只有可能和逻辑地址打交道,比如在 C 语言中,指针里面存储的数值就可以理解成为内存里的一个地址,这个地址也就是我们说的逻辑地址,逻辑地址由操作系统决定。物理地址指的是真实物理内存中地址,更具体一点来说就是内存地址寄存器中的地址。物理地址是内存单元真正的地址。
3.6 CPU 寻址了解吗?
这部分内容参考了 Microsoft 官网的介绍,地址:https://docs.microsoft.com/zh-cn/windows-hardware/drivers/gettingstarted/virtual-address-spaces?redirectedfrom=MSDN
现代处理器使用的是一种称为 虚拟寻址(Virtual Addressing) 的寻址方式。
使用虚拟寻址,CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。
实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有一个被称为 内存管理单元(Memory Management Unit, MMU) 的硬件。**MMU需要借助存放在内存中的页表来动态翻译虚拟地址,该页表由操作系统管理。**如下图所示:
TLB:转译后备缓冲区
3.7 为什么进程没办法访问不属于它的内存?
这主要跟内存的映射有关,准确地说应该是跟页表的实现方式有关。
- 如果页表采用一般的实现方式,那么每个进程都会有一个属于它自己的页表,只能映射到进程自己的地址空间。
- 如果采用的是倒置页表,在映射的时候,由于倒置页表采用物理帧做索引,<pid, p> 进程 id 以及逻辑页作为value,所以进程没办法搜索到不属于自己的物理帧,也就无法访问不属于它的内存。
- 同理,其他的实现方式,操作系统也会实现相应的地址空间隔离。
3.8 一个进程有多少个段表和页表
这主要跟操作系统的内存管理有关。
- 如果存储器采用基本分页机制,那么操作系统会为每个进程或任务建立一个页表(这个页表可能是一级的也可能是多级的)。整个操作系统中有多个进程在运行,那么系统就会有多个页表。页表在内存中的存储位置由寄存器CR3给出。
- 如果存储器采用基本分段机制,那么操作系统会为每个进程或任务建立一个段表(一般不用多级),用于记录数据段、代码段等各类段在内存中的具体位置。
- 如果采用段页式结合的机制,那么一般一个进程或任务,操作系统会给其建立一个段表,而段表中的每个段又会对应一个页表,也就是说,段页式机制的每个进程有一个段表,有多个页表。
3.9 为什么使用分段比使用纯分页更容易共享可重入模块?
可重入模块一般需要实现共享以及保护。
代码共享
因为分段方式中,每个段都是逻辑上的一个整体,比如一个函数、一个子程序等等,并且大小不一。而代码的共享往往就是以函数或子程序为单位的,不管被共享的段有多大,只要为共享代码的进程各设置一个段表项,并让相应段的基址指向同一个内存的位置就可以了,非常容易。
而在分页方式中,由于页面大小是固定的,被共享的代码可能在多个页面中,比如两个进程,共享代码有40页,就需要让两个页表中的40项都一一对应地指向同一个内存地址,不太方便。
信息保护
信息保护也是以信息的逻辑单位为基础的,比如函数、文件、子程序等。比如要保护一个函数A,在分段系统中,我们只需要在包含了函数A的段上标志只读、只写、只执行标志就可以了。
但是在分页系统中,函数A可能要占用多个页面,而且其中的第一个和最后一个页面还可能装有其他程序段的数据,它们可能有着不同的保护属性,难以实施统一的保护。因此,分段管理方式能更加有效和方便地实现对信息的保护功能。