内存管理基础
内存管理概念
内存的分配、回收、地址转换。
常见的内存管理机制
连续分配管理方式和非连续分配管理方式。
块式管理【连续】、页式管理、段式管理、段页式管理【非连续】。
页式管理:操作系统页为单位。
段式管理:函数段。
段页式管理:先分段,然后分页。
快表和多级页表
快表
为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的 Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。
使用快表之后的地址转换流程是这样的:
- 根据虚拟地址中的页号查快表;
- 如果该页在快表中,直接从快表中读取相应的物理地址;
- 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
- 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。
多级页表
引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景,具体可以查看下面这篇文章多级页表如何节约内存:https://www.polarxiong.com/archives/多级页表如何节约内存.html
分页机制和分段机制的共同点和区别
- 共同点 :
- 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
- 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
- 区别 :
- 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
- 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
- 分页机制是一维的,页号-块号;分段机制是二维的,段号-段内地址。
交换空间的概念、用途
概念:
- 操作系统把物理内存(physical RAM)分成一块一块的小内存,每一块内存被称为页(page)。当内存资源不足时,Linux 把某些页的内容转移至硬盘上的一块空间上,以释放内存空间。硬盘上的那块空间叫做交换空间(swap space), 而这一过程被称为交换(swapping)。物理内存和交换空间的总容量就是虚拟内存的可用容量。
用途:
- 物理内存不足时一些不常用的页可以被交换出去,腾给系统。
- 程序启动时很多内存页被用来初始化,之后便不再需要,可以交换出去。
19 波动的响应延迟:如何应对变慢的Redis?(下) 中提到了 Redis 内存不够下,操作系统使用 swap 机制导致 Redis 响应变慢的情况。
逻辑(虚拟)地址和物理地址 & 映射关系
虚拟地址就是程序虚拟内存中的地址。
物理地址指的是真实物理内存中地址,更具体一点来说就是内存地址寄存器中的地址。
以(虚拟)分页存储为例,逻辑地址(逻辑页号,页内地址),页表(逻辑页号,物理页号),物理地址(物理页号,业内地址)
假设一页 1024,物理地址为 2058,那么可以得到
- 逻辑页号 = 2058 / 1024 = 2
- 页内地址 = 2058 % 1024 = 10
虚拟地址空间切换会比较耗时
进程都有自己的虚拟地址空间,把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用 Cache 来缓存常用的地址映射,这样可以加速页表查找,这个 Cache 就是 TLB (translation Lookaside Buffer,TLB 本质上就是一个 Cache,是用来加速页表查找的)。
由于每个进程都有自己的虚拟地址空间,那么显然每个进程都有自己的页表,那么当进程切换后页表也要进行切换,页表切换后 TLB 就失效了,Cache 失效导致命中率降低,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致 TLB 失效,因为线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。
CPU 寻址了解吗? 为什么需要虚拟地址空间?
CPU 寻址就是将虚拟地址映射到物理地址。实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有一个被称为内存管理单元的硬件。
为什么要有虚拟地址空间呢?
没有虚拟地址空间的时候,程序都是直接访问和操作的都是物理内存。
- 用户程序可以访问任意内存,从而可能破坏操作系统。
- 多个程序同时操作物理内存,可能存在同时读写一个地址的数据,导致出错。
缓冲区溢出概念、危害、原因
概念:
- 当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
危害:
- 程序崩溃,导致拒绝额服务
- 跳转并且执行一段恶意代码
主要原因:
- 程序中没有仔细检查用户输入。