操作系统内存管理
什么是物理内存
我们常说的物理内存大小就是指内存条的大小,但是也要看CPU地址总线的位数。
使用物理内存的缺点
- 单个进程直接操作物理地址,可能破坏系统
- 多进程运行,多个进程同时操作同一地址空间,产生并发读写问题
虚拟内存技术
虚拟内存
虚拟出来的内存,确保每个进程都有自己的地址空间,一般是4G。操作系统自动将虚拟地址空间映射到物理地址空间,程序关注的只是虚拟内存,请求的也是虚拟内存,但是真正实用的是物理内存。
linux将虚拟内存氛围两个部分,内核空间和用户空间。系统中每个用户进程都有自身的虚拟地址范围,从0到TASK_SIZE。用户空间之上的区域(从TASK_SIZE到232或者264)保留给内核专用,用户进程不能访问。
虚拟内存技术特点
- 大的用户空间:32位虚拟地址可以访问4G
- 部分交换
- 连续性:对连续的虚拟地址来映射物理内存中的不连续的大内存缓冲区
- 安全性:不同进程的虚拟地址彼此隔离
虚拟内存如何映射到物理内存
CPU中有一个内存管理单元,MMU(Memory Management Unit),虚拟内存不是直接送到内存总线,而是先给到MMU,由MMU来把虚拟地址映射到物理地址。
MMU通过页表将虚拟地址转换为物理地址,32位的虚拟地址分成两部分(虚拟页号和偏移量),MMU通过页表找到了虚拟页号对应的物理页号,物理页号+偏移量就是实际的物理地址。
页表的目的就是虚拟页面映射为物理内存的页框,页表可以理解为一个数学函数,函数的输入是虚拟页号,函数的输出是物理页号,通过这个函数可以把虚拟页面映射到物理页号,从而确定物理地址。
内存分页
分页是把整个虚拟和物理内存空间切成一段段固定尺寸大小,这个连续并且尺寸固定的内存空间,我们叫页。在linux下,每一页的大小为4KB。
在分页机制下,虚拟地址分为两部分,页号和页内偏移。页号作为页表的索引,页表 包含物理页每页所在物理内存的基地址,这个基地址与页内偏移的组合就形成了物理内存地址。这种被称为简单分页。
简单分页缺陷
存在空间上的缺陷。
因为操作系统是可以同时运⾏⾮常多的进程的,这就意味着⻚表会⾮常的庞⼤。在32位的环境下,虚拟地址空间共有4GB,假设⼀个⻚的⼤⼩是4KB(2^12),那么就需要⼤约100万 (2^20)个⻚,每个「⻚表项」需要4个字节⼤⼩来存储,那么整个4GB空间的映射就需要有 4MB的内存来存储⻚表。这4MB⼤⼩的⻚表,看起来也不是很⼤。但是要知道每个进程都是有⾃⼰的虚拟地址空间的,也就说都有⾃⼰的⻚表。那么, 100 个进程的话,就需要 400MB 的内存来存储⻚表,这是⾮常⼤的内存了,更别说64位的环境了。
多级页表
要解决上⾯的问题,就需要采⽤⼀种叫作多级⻚表(Multi-Level Page Table)的解决⽅案。
对于单页表的实现方式,在32位和页大小4KB的环境下,一个进程的页表需要装下100多万个页表项,并且每个页表项是占用4字节大小,相当于每个页表需占用4MB大小空间。
我们把这个100多万个页表项的单级页表再分页,将页表(一级页表)分为1024个页表(二级页表),每个表(二级页表)中包含1024个页表项,形成二级分页。
分了二级表,映射4GB地址空间需要4KB(一级页表)+4MB(二级页表)的内存,这样占用空间不是更大了吗?
当然如果 4GB 的虚拟地址全部都映射到了物理内存上的话,⼆级分⻚占⽤空间确实是更⼤
了,但是,我们往往不会为⼀个进程分配那么多内存。
如果使⽤了⼆级分⻚,⼀级⻚表就可以覆盖整个4GB虚拟地址空间,但如果某个⼀级⻚表的
⻚表项没有被⽤到,也就不需要创建这个⻚表项对应的⼆级⻚表了,即可以在需要时才创建
⼆级⻚表。所以⻚表⼀定要覆盖全部虚拟地址空间,不分级的⻚表就需要有100多万个⻚表项来映射,⽽⼆级分⻚则只需要1024个⻚表项(此时⼀级⻚表覆盖到了全部虚拟地址空间,⼆级⻚表在需要时创建)。
我们把⼆级分⻚再推⼴到多级⻚表,就会发现⻚表占⽤的内存空间更少了,这⼀切都要归功
于对局部性原理的充分应⽤。
对于64位的系统,两级分页肯定不够了,就变成了四级目录,分别是:
- 全局⻚⽬录项 PGD(Page Global Directory)
- 上层⻚⽬录项 PUD(Page Upper Directory)
- 中间⻚⽬录项 PMD(Page Middle Directory)
- ⻚表项 PTE(Page Table Entry)
TLB
多级页表虽然解决了空间上的问题,但是虚拟地址到物理地址的转换就多了几道转换的工序,这显然就降低了这两地址转换的速度,也就是带来了时间上的开销。
程序是有局部性的,即在⼀段时间内,整个程序的执⾏仅限于程序中的某⼀部分。相应地,
执⾏所访问的存储空间也局限于某个内存区域。
我们就可以利⽤这⼀特性,把最常访问的⼏个⻚表项存储到访问速度更快的硬件,于是计算
机科学家们,就在 CPU 芯⽚中,加⼊了⼀个专⻔存放程序最常访问的⻚表项的Cache,这个
Cache 就是 TLB(Translation Lookaside Buffer) ,通常称为⻚表缓存、转址旁路缓存、快表等。
在 CPU 芯⽚⾥⾯,封装了内存管理单元(Memory Management Unit)芯⽚,它⽤来完成地
址转换和 TLB 的访问与交互。有了TLB后,那么CPU在寻址时,会先查TLB,如果没找到,才会继续查常规的⻚表。TLB 的命中率其实是很⾼的,因为程序最常访问的⻚就那么⼏个。