前言

我们继续看Linux的性能指标,内存也是重要的组成部分之一。本文从常用命令top、free出发,分析内存有哪些性能指标。
本文基于Ubuntu 16.04。

Linux内存性能指标有哪些

使用top,按下E切换到MB单位,可以看到内存相关的指标如下:

  1. top - 05:09:25 up 7 days, 14:45, 1 user, load average: 0.00, 0.00, 0.00
  2. Tasks: 95 total, 1 running, 55 sleeping, 0 stopped, 0 zombie
  3. %Cpu(s): 0.0 us, 0.2 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
  4. MiB Mem : 3913.410 total, 3090.164 free, 150.316 used, 703.430 buff/cache
  5. MiB Swap: 0.000 total, 0.000 free, 0.000 used. 3497.512 avail Mem
  6. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  7. 28517 user 20 0 40496 3612 3036 R 0.3 0.1 0:00.06 top
  • MiB Mem:系统物理内存相关指标
    • total:总内存
    • free:可用内存
    • used:已使用内存
    • buff/cache:缓存区/缓存占用内存
  • MiB Swap:系统交换空间相关指标
    • total:总内存
    • free:可用内存
    • used:已使用内存
    • avail Mem:交换空间有效内存,包含可回收的页缓存和slabs缓存(下文会提到)
  • 进程的指标:
    • VIRT:虚拟内存大小,只要是进程申请过的内存,即使还没真正分配物理内存,也会计算在内
    • RES:常驻内存大小,也就是进程实际使用的物理内存大小,但不包括swap和共享内存
    • SHR:共享内存大小,比如与其它进程共同使用的共享内存、加载的动态链接库以及程序的代码段等
    • %MEM:进程使用物理内存占系统总内存的百分比

通过free -h,可以看到系统内存相关的指标如下:

  1. # free -h
  2. total used free shared buff/cache available
  3. Mem: 3.9G 152M 3.0G 15M 703M 3.4G
  4. Swap: 0B 0B 0B
  • Mem
    • total:总内存
    • used:已使用内存的大小,包含了共享内存
    • free:未使用内存的大小
    • shared:共享内存的大小
    • buff/cache:缓冲区和缓存的大小
    • available:新进程可用内存的大小,不仅包括未使用内存,还包括可回收的缓存,但不包括swap空间大小

总的来说,内存性能指标包括

  • 系统内存性能指标
  • 进程内存性能指标
  • Swap(交换空间)性能指标

在讲这些指标之前,我们先来看Linux内存的工作原理,可以帮助我们更好理解这些性能指标

Linux内存是怎么工作的

计算机中运行着进程,进程的运行需要依赖内存去记录运行时所需的数据。我们平时接触到的内存概念一般是机器的配置,比如8G内存,对于这8G内存是属于物理内存。而对于进程来说,并不是直接访问物理内存,而是通过虚拟内存,两者之间通过页表做映射。如图
image.png

那么为什么不直接访问物理内存呢?使用虚拟内存有以下的好处

  • 虚拟内存可以为进程提供独立的内存空间,简化内存分配过程
  • 不限于物理内存的空间限制,可以利用磁盘加物理内存,为进程提供看起来访问速度快,并且容量足够大的存储
  • 虚拟内存可以控制进程对物理内存的访问,隔离不同进程的访问权限,提高系统的安全性

虚拟地址与物理地址映射用的页面存储在MMU中。当进程访问的虚拟地址在页表中找不到时,会产生一个缺页异常,进入内核空间分配物理内存,更新进程页表,最后再返回用户空间,恢复进程的运行。
在MMU中,还通过TLB做页表的高速缓存,提升查询物理地址的性能。TLB空间有限,通过减少进程上下文切换,来减少TLB的刷新次数,就可以提高TLB缓存的使用率,进而提高CPU的内存访问性能。

对于每个进程,都有独自的虚拟内存空间,虚拟内存空间分布如图(32位系统为例)
image.png
最上方是内核空间,下方是用户空间。用户空间内存,从低到高分别是五种不同的内存段。

  1. 只读段:包括代码和常量等
  2. 数据段:包括全局变量等
  3. 堆:包括动态分配的内存,从低地址开始向上增长
  4. 文件映射:包括动态库、共享内存等,从高地址开始向下增长
  5. 栈:包括局部变量和函数调用的上下文等

Linux通过伙伴(Buddy)系统管理内存分配,伙伴系统使用页为单位(4KB)来管理内存。
关于分配内存,malloc是C标准库内存分配函数

  • 对于小块内存(小于128KB),malloc通过brk()分配,通过移动堆顶的位置来分配内存。这些内存释放后不会立刻归还系统,而是被缓存起来,这样就可以重复使用。这种方式可以减少缺页异常的发生,但频繁的内存分配和释放会造成内存碎片。
  • 对于大块内存(大于128KB),malloc通过内存映射mmap()分配,也就是在文件映射段找一块空闲内存分配出去,在释放时会直接归还系统,所以每次mmap都会发生缺页异常。这种方式可以保证分配连续大内存段时,减少由于内存碎片导致的分配失败的情况出现。但频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大,这也是malloc只对大块内存使用mmap的原因。

对于比页更小的对象,比如1KB,如果也分配单独的页,会有内存浪费。针对这个问题,在内核空间中,Linux通过slab分配器来管理小对象。

对于释放缓存,应用程序在用户内存后,还需要调用free()或unmap()释放不用的内存,避免内存泄漏。

而对于回收内存,系统可通过以下三种方式回收

  • 回收缓存:比如使用LRU算法,回收最近最少使用的内存页面
  • 回收不常用的内存:把不常用的内存通过swap直接写到磁盘中
  • 杀死进程:通过OOM,直接杀掉占用大量内存的进程

以上就是关于Linux内存工作原理的简单介绍,包括进程使用虚拟内存、虚拟到物理内存的映射方式,以及分配和回收内存的介绍。实际上Linux内存的工作原理还要复杂得多,这里仅作一个整体的认识。

内存性能指标

通过了解工作原理,我们会了解到虚拟内存、swap空间等概念的实际含义,接下来我们来理解Linux的性能指标。

系统内存性能指标

  • 已用内存和剩余内存
  • 共享内存
  • 可用内存:新进程可使用的最大内存,它包括剩余内存和可回收缓存
  • 缓存(cache):包括两部分,一部分是磁盘读取文件的页缓存,用户缓存从磁盘读取的数据,可以加快以后再次访问的速度;另一部分,则是slab分配器中的可回收内存
  • 缓冲区(buff):对原始磁盘块的临时存储,用来缓存将要写入磁盘的数据。这样,内核就可以把分散的写集中起来,统一优化磁盘写入

进程内存性能指标

  • 虚拟内存
  • 常驻内存:进程实际使用的物理内存,不包括swap和共享内存
  • 共享内存
  • swap内存:通过swap换出磁盘的内存

swap性能指标

在内存分配的原理中,上面讲过,系统调用内存分配请求后,并不会立刻为其分配物理内存,而是在请求首次访问时,通过缺页异常来分配。缺页异常又分为下面两种场景:

  • 次缺页异常:可以直接从物理内存中分配
  • 主缺页异常:需要磁盘I/O接入(比如swap)

这样,主缺页异常升高,意味着需要磁盘I/O,那么内存访问也会慢很多。
因此,对于swap来说,也属于重要的性能指标,具体包括

  • 已用空间
  • 剩余空间
  • 换入速度:即数据从磁盘换到内存的速度
  • 换出速度:即数据从内存换到磁盘的速度

总结

本文主要讲了Linux内存性能指标,通过如下的脑图可以有个整体的视角 理解Linux内存性能指标 - 图3

参考链接