Linux性能优化从入门到实战:08 内存篇:内存基础

内存主要用来存储系统和应用程序的指令、数据、缓存等。

内存映射

  物理内存也称为主存,动态随机访问内存(DRAM)。只有内核才可以直接访问物理内存。
  Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程就可以很方便地访问内存,更确切地说是访问虚拟内存。虚拟地址空间的内部又被分为内核空间用户空间两部分。
  Linux性能优化从入门到实战:08 内存篇:内存基础
  进程在用户态时,只能访问用户空间内存;只有进入内核态后,才可以访问内核空间内存。虽然每个进程的地址空间都包含了内核空间,但这些内核空间,其实关联的都是相同的物理内存。当进程切换到内核态后,就可以很方便地访问内核空间内存。
  并不是所有的虚拟内存都会分配物理内存,只有那些实际使用的虚拟内存才分配物理内存,并且分配后的物理内存,是通过内存映射来管理的。内存映射,其实就是将虚拟内存地址映射到物理内存地址。为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址与物理地址的映射关系。
  页表实际上存储在 CPU 的内存管理单元 MMU 中,这样,正常情况下,处理器就可以直接通过硬件,找出要访问的内存。而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。
  Linux性能优化从入门到实战:08 内存篇:内存基础
  CPU 上下文切换中的 TLB(Translation Lookaside Buffer,后备缓冲器)是 MMU 中页表的高速缓存。由于进程的虚拟地址空间是独立的,而 TLB 的访问速度又比 MMU 快得多,所以,通过减少进程的上下文切换,减少 TLB 的刷新次数,就可以提高 TLB 缓存的使用率,进而提高 CPU 的内存访问性能。
  MMU 规定了一个内存映射的最小单位,也就是页,通常是 4 KB 大小。这样,每一次内存映射,都需要关联 4 KB 或者 4KB 整数倍的内存空间。
  4 KB大小的页,会导致整个页表会变得非常大。为了解决页表项过多的问题,Linux 提供了两种机制,也就是多级页表和大页(HugePage)。
  多级页表就是把内存分成区块来管理,将原来的映射关系改成区块索引和区块内的偏移。由于虚拟内存空间通常只用了很少一部分,那么,多级页表就只保存这些使用中的区块,这样就可以大大地减少页表的项数。Linux 用四级页表来管理内存页,虚拟地址被分为 5 个部分,前 4 个表项用于选择页,而最后一个索引表示页内偏移。
  Linux性能优化从入门到实战:08 内存篇:内存基础
  大页,就是比普通页更大的内存块,常见的大小有 2MB 和 1GB。大页通常用在使用大量内存的进程上,比如 Oracle、DPDK 等。
  通过这些机制,在页表的映射下,进程就可以通过虚拟地址来访问物理内存了。
  

虚拟内存空间分布

  用户空间内存又被分成了多个不同的段。在这五个内存段中,堆和文件映射段的内存是动态分配的。如 C 标准库的 malloc() 或者 mmap() 分别在堆和文件映射段动态分配内存。64 位系统的内存分布也类似,只不过内存空间要大得多。
  Linux性能优化从入门到实战:08 内存篇:内存基础
  

内存分配与回收