Linux 内存管理

Memory 相关的术语说明

  • Main Memory - 也经常称为 Physical Memory,计算机上的 Fast Data Storage Area。
  • Virtual Memory - Main Memory 的一个抽象层,他几乎有无限大的空间,Virtual Memory 不是 Main Memory
  • Resident Memory - 驻留(Reside)在 Main Memory 中的内存,相当于实际使用的物理内存(Main Memory/Physical Memory),如 top 命令中的 RESps aux 命令中的 RSS 就是指 Resident Memory.
  • Anonymous Memory - 未关联文件系统位置和路径的内存,通常指 Process Address Space 中的程序运行过程中的数据(Working Data),通常被称为 Heap
  • Address Space - 内存地址空间,内存地址相关的上下文(Context),包含程序(Processes)和内核(Kernel)使用的 Virtual Address Space
  • Segment - 用于标识 Virtual Memory 中的有特殊作用的一个区域,如可执行程序(Executable)或可写(Writable)的 Page
  • Instruction Text - CPU 指令(Instructions) 在内存中的引用地址,通常位于 Segment
  • OOM - Out Of Memory,当内核检测到系统可用内存不足时采取的动作
  • Page - OS 和 CPU 使用和分配内存的单位,早期大小一般为 4 或 8 Kbytes,现代化的 CPU 和 OS 通常支持 Multi Page Sizes
  • Page Fault - 通常在需要访问的内容不存在于 Virtual Memory 中时,系统产生一个中断,导致所需内容加载入内存
  • Paging - 当内存中的内容不再使用或内存空间不足时进行的在内存和 Storage Devices 中的内容交换,主要是为了空出内存供需要内存的进程使用
  • Swapping - Linux 中将不再使用或内存空间不足时,将部分内存中的内容 Paging 到 Swap Devices
  • Swap - Linux 中 Swapping 时,将内容转移到的目标,可能是 Storage Devices 上的一个区域,被称为 Physical Swap Device,或者是一个文件系统文件,称为 Swap File。

Memory 部分概念详细说明参考

MMU

Memory Management Unit(MMU) 负责虚拟内存地址(Virtual Memory Address)到物理内存地址(Physical Memory Address)的转换

Freeing Memory

当系统上可用内存低或不足时,系统会采用一系列的手段释放内存。主要包括下图所示方式

  • Free List
    不在使用中的 Pages 列表,也称为 Idle Memory,这部分内存可以被系统立即分配给需要的程序使用
  • Page Cache
    文件系统缓存(Filesystem Cache)。有个 swappiness 的参数可以配置系统是使用 Page Cache 还是 Swapping 来释放内存
  • Swapping
    通过内核进程 kswapd 实现 Paging Out 到 Swap Device 或者 File System-Based Swap File,这只有在系统上有 Swap 时才有用。
  • Reaping
    也被称为 Shrinking ,当系统可用内存小到一个临界值后,内核就会开始释放可以回收的内存
  • OOM Killer
    Out Of Memory Killer ,系统内存不足时,系统会使用 OOM Killer 机制来 kill 掉某个进程来释放内存。

进程的内存分层结构

进程的内存结构一般被分成多个 sections,包括

  • Text section - 存放程序代码(the executable code)
  • Data section - 存放全局变量(global variables)
  • Heap section - 程序运行过程中动态分配的内存
  • Stack section - 调用程序功能时的临时数据存储,如函数参数、返回地址、本地变量等。

下图展示了 C 程序(Program)在内存中的分层结构(layout of a C program in memory)

  • 其中, Data section 被分成了 2 部分,包括 (a) initialized data(b) uninitialized data

使用 GNU 工具 size 可以检查 Projram 在磁盘上的 内存布局。这些值在程序编译时确定,并不会在程序运行时变化,因此它们是固定不变的。

# size /usr/sbin/sshd
text data bss dec hex filename
817397 15460 37664 870521 d4879 /usr/sbin/sshd

输出信息中:

  • text : 代表 Text section 的大小
  • data : 初始化数据段(initialized data)的大小,包含已初始化的全局和静态变量。
  • bss : 未初始化数据段的大小,包含未初始化的全局和静态变量。
  • dec : 上述所有部分的总大小,以十进制表示。
  • hex : 上述所有部分的总大小,以十六进制表示。

Memory Paging

Memory Paging 说明

查看内存分页大小

# getconf PAGESIZE
4096

清除系统内存中的分页缓存

如果系统内存不足或者定位内存相关问题,需要清空内存中的分页缓存(Memory Page Cache,将当前没有使用的所有内存分页要么写回到磁盘,要么丢弃),可以使用以下方法

  • echo 3 > /proc/sys/vm/drop_caches

内存状态监测工具

vmstat

vmstat 是一个系统全局性(System Wide)工具,主要用来监测 Virtual 和 Physical Memory 的统计数据

OOM

OOM (Out-Of-memory) 是 Linux 内核机制(kernel reaper routine),用来确保系统始终有可用内存。当系统可用内存太低时,系统使用 OOM 机制 Kill 掉选中的进程以释放内存空间。Linux 中的每个进程有一个 OOM Score值,值越大,被 Kill 掉的可能性越大,OOM 值是根据所使用的内存占比计算而来,占用内存比例越高,OOM Score 越大。可以在 /proc/<PID>/oom_score 中看到 OOM Score 值

内存压力测试工具

memtester

使用 docker 运行工具

$ docker run --rm -it dockerpinata/memtester:1 memtester
memtester version 4.3.0 (64-bit)
Copyright (C) 2001-2012 Charles Cazabon.
Licensed under the GNU General Public License version 2 (only).

pagesize is 4096
pagesizemask is 0xfffffffffffff000
need memory argument, in MB

Usage: memtester [-p physaddrbase [-d device]] <mem>[B|K|M|G] [loops]

stress 工具

stress 是一个用于模拟系统负载的工具,可以使用它来创建临时的内存负载。通过模拟负载,系统将使用更多的内存。

yum install -y stress

使用以下命令可以创建一个临时的内存负载

stress --vm 1 --vm-bytes <MEMORY_SIZE>

dd

dd 命令可以用于创建大文件并占用磁盘空间,从而间接提升系统的内存使用率。您可以使用以下命令创建一个指定大小的临时文件

dd if=/dev/zero of=tempfile bs=1M count=<MEMORY_SIZE>

tmpfs

Linux 中 tmpfs 是一种基于内存的临时文件系统,它将内存作为存储介质,可以在需要快速读写文件的场景下使用。

注意事项

  • tmpfs 是基于内存的临时文件系统,因此上面的数据在系统重启后将丢失
  • tmpfs 文件系统使用的内存达到上限值,写入操作会失败,因此需要确保分配给 tmpfs 文件系统使用的内存适合需求
  • 要确保系统有足够的可用内存来支持挂载 tmpfs 文件系统。

tmpfs 使用步骤

  1. 创建一个目录作为文件系统挂载点
    mkdir /mnt/ramdisk/
  2. 使用 mount 命令以 tmpfs 的类型挂载文件系统
    mount -t tmpfs -o size=1G tmpfs /mnt/ramdisk/
    这将在 /mnt/ramdisk 目录下挂载一个 1GB 大小的 tmpfs 文件系统。根据需要调整 size 参数的值。之后便可以像操作其他文件系统一样在 /mnt/ramdisk 目录下读写文件。任何写入该目录的数据都将存储在内存中。

参考链接|Bibliography

Systems Performance: Enterprise and the Cloud v2

脚注