free 和 meminfo查看内存情况。
linux的内存情况我们通常使用free命令来查看
$ free -m
total used free shared buffers cached
Mem: 925 388 537 25 27 207
-/+ buffers/cache: 153 771
Swap: 99 0 99
proc文件系统中的 meminfo文件包含关于系统对内存使用情况的信息。free命令就是读取这个文件来呈现当前系统包含物理内存和SWAP内存在内的空闲内存和已使用内存。
$ cat /proc/meminfo
MemTotal: 947732 kB //总的可以使用的RAM大小,物理内存减去部分保留位和内核二进制代码。
MemFree: 550120 kB //LowFree + HighFree的 总和 ,HighTotal, HighFree, LowTotal, LowFree 从内核V2.6.19版本开始支持,需配置 CONFIG_HIGHMEM宏。在当前我这个系统中应该是没有配置这个宏的。Highmem表示高于 ~860MB的物理内存,用于用户空间进程或者缓存页,内核必须使用特殊的方式才能访问 Highmem,故而访问起来会比lowmem更慢。HighFree就是空闲的HighMem, lowmem能做highmem能做的任何事,同时也能让内核方便地存储其数据结构。slab分配的内存都是基于这部分来的。当lowmem不足时,系统可能会出现异常。
MemAvailable: 728780 kB
Buffers: 27804 kB //给裸磁盘块使用的临时缓存空间,不能变得过大(比如超过20MB)
Cached: 212476 kB //用于从磁盘读取的文件在内存中的缓存。不包括 SwapCached
SwapCached: 0 kB //被swap到磁盘上的内存,如果已经被swap回来,但是仍在swapfile中也保留了一份。(在内存压力大的时候这样可以节省I/O,因为很可能这些内存马上又要被换出去)
Active: 221860 kB // 更近和更频繁使用的内存,如果非必要不会被使用。
Inactive: 137452 kB // 更没有被频繁使用的内存,更有可能被用于其他用途。
Active(anon): 119708 kB
Inactive(anon): 25052 kB
Active(file): 102152 kB
Inactive(file): 112400 kB
Unevictable: 0 kB // 需要支持配置了该宏CONFIG_UNEVICTABLE_LRU
Mlocked: 0 kB // 需要支持配置了该宏CONFIG_UNEVICTABLE_LRU
SwapTotal: 102396 kB // 总的可用SWAP空间。
SwapFree: 102396 kB //未使用的SWAP空间。
Dirty: 8 kB //正在等待被写回磁盘的内存
Writeback: 0 kB //正在被写回磁盘的内存
AnonPages: 118928 kB // Non-file backed pages mapped into user-space page tables,并不与文件相关联的映射到用户空间的内存,在mmap系统调用中有MAP_ANONYMOUS 选项,从一个unix.stackexchange上一个答主的说法,malloc其实就是会去调用mmap去请求分配对应的内存,所以AnonPages可以理解为用户态进程最频繁使用的malloc出来的内存。
Mapped: 92468 kB // 被映射到内存中的文件(mmap的方式),比如lib库
Shmem: 25732 kB
Slab: 20004 kB // 内核数据结构的缓存
SReclaimable: 10132 kB // Slab的一部分,可能回被重新回收使用,比如caches
SUnreclaim: 9872 kB // 即使内存不足,也不能被重新回收使用
KernelStack: 1864 kB // 内核栈的内存
PageTables: 3712 kB //
NFS_Unstable: 0 kB // 接收到 但还未持久化的NFS页。
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 576260 kB // 这是当前系统上能允许被分配的内存总量,这个限制是否生效
与 /proc/sys/vm/overcommit_memory 参数中设置的模式相关,仅在 该类型被设置为模式2 ,即永远不触发 overcommit时,这个 阈值才会被应用。它的计算公式可以通过/proc/sys/vm/overcommit_memory来查看。
// overcommit_memory 类型有3种,影响是否允许分配超过系统物理内存总大小的内存分配策略。0代表启发式overcommit, 1 Always overcommit 允许overcommit. 2 不允许overcommit,提交给系统的内存请求不允许超过总大小。
Committed_AS: 1254104 kB // 当前系统中已经分配的内存,commited memory是已经分配给进程的内存总和的大小, 即使这些内存还没有被使用。比如一个进程请求分配了1GB的空间,但只使用了300MB的话,只会在这里计入300MB,即使实际分配了1GB的空间。
// 这1GB的内存已经被VM确认,随时可以分配给申请的进程。如果overcommit_memory设置为模式2,即严格限制overcommit的模式。超过CommitLimit的分配请求是不被允许的。这可以应用于如下场景,比如我们想要保证一个进程一旦对应已经成功分配了内存,就不会再因为内存不足而报错。
VmallocTotal: 1114112 kB // vmalloc内存区域的总大小。vmalloc分配连续的虚拟内存,但可能是不连续的物理内存。只在分配大块内存空间不得已时使用。
VmallocUsed: 0 kB // 已使用的vmalloc内存大小
VmallocChunk: 0 kB // 大块的连续的空闲的vmalloc块
CmaTotal: 8192 kB //
CmaFree: 3728 kB
cached的产生
1、观察sftp下载文件内存中cache的影响
我们在通过下载一个10MB的文件前后分别使用free命令打印当前的内存状态。可以发现free的cached一栏增加了10MB的内存。那如何了解到是否就是这个文件的下载导致的呢?。我们可以使用vmtouch命令来进行查看。
~/package $ free -m
total used free shared buffers cached
Mem: 925 554 370 30 88 293
-/+ buffers/cache: 172 753
Swap: 99 0 99
~/package $ free -m
total used free shared buffers cached
Mem: 925 565 360 30 88 303
-/+ buffers/cache: 172 752
Swap: 99 0 99
vmtouch
2、vmtouch命令简介。
vmtouch是一个作者hoytech在github上开源的用于在unix和类unix系统上学习和控制文件系统缓存的工具。
下面是其帮助界面 https://github.com/hoytech/vmtouch/blob/master/vmtouch.pod
vmtouch的主要功能如下:
- 查看一个文件或者目录的哪些部分在内存中
- 手动把文件调入内存
- 手动把文件清除出内存
- 把文件锁住在内存中而不被换到磁盘上
./vmtouch-1.3.1/vmtouch -h
./vmtouch-1.3.1/vmtouch: no files or directories specified
vmtouch v1.3.1 - the Virtual Memory Toucher by Doug Hoyte
Portable file system cache diagnostics and control
Usage: vmtouch [OPTIONS] ... FILES OR DIRECTORIES ...
Options:
-t touch pages into memory
-e evict pages from memory
-l lock pages in physical memory with mlock(2)
-L lock pages in physical memory with mlockall(2)
-d daemon mode
-m <size> max file size to touch
-p <range> use the specified portion instead of the entire file
-f follow symbolic links
-F don't crawl different filesystems
-h also count hardlinked copies
-i <pattern> ignores files and directories that match this pattern
-I <pattern> only process files that match this pattern
-b <list file> get files or directories from the list file
-0 in batch mode (-b) separate paths with NUL byte instead of newline
-w wait until all pages are locked (only useful together with -d)
-P <pidfile> write a pidfile (only useful together with -l or -L)
-v verbose
-q quiet
3、vmtouch的常用使用场景。
我们下载vmtouch的1.3.1的版本编译后,查看刚才这个文件的的状态。可以看到 nmap这个文件在常驻页面中有2643个页,合计10M内存,通过getconf PAGESIZE 可以直到一个页的大小为4K。
~/package $ ./vmtouch-1.3.1/vmtouch ./nmap-7.93.tar.bz2
Files: 1
Directories: 0
Resident Pages: 2643/2643 10M/10M 100%
Elapsed: 0.001669 seconds
通过vmtouch -v ./ 可以递归查看某一个目录下所有文件的在内存中的暂存情况,可以用于在 调用drop_cache之后,发现cached中仍有很大的内存,确认具体是什么文件被加载到了内存,同时不能被清除出缓存。
通过vmtouch -t命令可以把文件提前加载到cache,实现预读的效果;通过vmtouch -e file 可以将文件的cache缓存清除出内存;通过vmtouch -l file 可以将文件的缓存锁在内存中不被换出。
3.1、 vmtouch -l file
首先来看使用vmtouch锁定文件到内存对 meminfo的影响,在meminfo中有一行为Mlocked,其表示被锁定在内存中的内存大小,即该块内存空间不会被交换到swap空间,也不会被回收。从如下的终端输出可以知道一开始Mlocked内存大小为0kB,经过vmtouch锁住之后,变为了10572kB,即10MB左右,恰好是锁住的 nmap-7.93.tar.bz2的文件的大小。
$cat /proc/meminfo
MemTotal: 947732 kB
...
Mlocked: 0 kB
...
$ ./vmtouch-1.3.1/vmtouch -l nmap-7.93.tar.bz2
LOCKED 2643 pages (10M)
$ cat /proc/meminfo
MemTotal: 947732 kB
...
Mlocked: 10572 kB
...
lock可以用于将最常使用的小文件常驻到内存,避免被换出导致磁盘的读写。
3.2、 vmtouch -e file
通过vmtouch -e可以将这个文件的缓存清除出内存,我们使用free 命令cached的变化来观察其效果。在使用free之前cached缓存为 311MB,使用vmtouch -e 将文件nmap-7.93.tar.bz2清除出缓存后,free显示的cached缓存为301MB。可见vmtouch -e 之功效。
$ free -m
total used free shared buffers cached
Mem: 925 586 338 37 91 311
-/+ buffers/cache: 183 742
Swap: 99 0 99
$ ./vmtouch-1.3.1/vmtouch -e nmap-7.93.tar.bz2
Files: 1
Directories: 0
Evicted Pages: 2643 (10M)
Elapsed: 0.006798 seconds
$ free -m
total used free shared buffers cached
Mem: 925 576 349 37 91 301
-/+ buffers/cache: 183 742
Swap: 99 0 99
该处理流程可应用于在读写完文件之后,明确短时间内不会再加载文件,干预内核的缓存处理流程,快速将文件的缓存快速回收,用于其他流程内存的使用。
3.3、vmtouch -t file
vmtouch -t file可以把文件预加载到内存的cache。通过free -m可以看到执行vmtouch前后的cached内存的差异。
$ free -m
total used free shared buffers cached
Mem: 925 567 357 36 91 300
-/+ buffers/cache: 175 750
Swap: 99 0 99
$ ./vmtouch-1.3.1/vmtouch -t nmap-7.93.tar.bz2
Files: 1
Directories: 0
Touched Pages: 2643 (10M)
Elapsed: 1.4855 seconds
$ free -m
total used free shared buffers cached
Mem: 925 577 348 36 91 310
-/+ buffers/cache: 174 750
Swap: 99 0 99
通过drop_cache的方式也可以手动释放内存,我们观察下使用drop_cache对cached缓存的影响。使用drop_cache必须拥有root权限。可以看到buffer和cached都进行了大量的释放,单独通过vmtouch观察 nmap文件在内存中的占用,可以看到占用大小为0.
# free -m
total used free shared buffers cached
Mem: 925 578 346 36 91 310
-/+ buffers/cache: 175 749
Swap: 99 0 99
#echo 3 > /proc/sys/vm/drop_caches
# free -m
total used free shared buffers cached
Mem: 925 279 645 36 1 114
-/+ buffers/cache: 164 761
Swap: 99 0 99
$ ./vmtouch-1.3.1/vmtouch nmap-7.93.tar.bz2
Files: 1
Directories: 0
Resident Pages: 0/2643 0/10M 0%
Elapsed: 0.000964 seconds
vmtouch的实现主要是基于 mincore 和 mlock系统调用。mincore判断某个地址是否驻在内存中。mlock 将调用进程的虚拟地址空间锁在内存中,避免被swap交换出去。会体现在meminfo的Mlocked字段。
NAME
mincore - determine whether pages are resident in memory
SYNOPSIS
#include <unistd.h>
#include <sys/mman.h>
int mincore(void *addr, size_t length, unsigned char *vec);
MLOCK(2) Linux Programmer's Manual MLOCK(2)
NAME
mlock, munlock, mlockall, munlockall - lock and unlock memory
SYNOPSIS
#include <sys/mman.h>
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
内存碎片。
针对内存的另一个问题是内存碎片,我们可能会遇到即使不考虑cached和buffer的内存,free能查看到的内存也还有足够多,但malloc却出现失败,这种情况可能是由于我们申请了一块大内存。而由于linux的内存伙伴系统分配机制,导致出现了大量的内存碎片,而无法申请到整块的内存以满足需求。我们可以通过 cat /proc/buddyinfo 来查看内存碎片的情况。buddyinfo提供了信息用来确认内存碎片问题。这一行展示了不同大小的块的可用块数,块的大小通过 (2^order)* PAGE_SIZE来判断。
如果是4KB的PAGE_SIZE,则如下内存伙伴系统包含了 164个 4KB块,218个 8 KB块,。。。和 88个4MB块。
$ cat /proc/buddyinfo
Node 0, zone Normal 164 218 36 631 862 267 54 22 8 8 88
内核中的伙伴系统内存分配算法会将一个块均分成两个块,或者将两个连续的块合并成更高阶的大块。用来服务于分配请求,和对抗内存碎片的产生。order等级和列相对应,起始的order为0。
通过查看manpage可以了解到,如果内存严重碎片化,高阶的chunks数量会变成0,请求分配大块连续内存的请求会失败。
/proc/buddyinfo
...
If the memory is heavily fragmentated, the counters for higher order
chunks will be zero and allocation of large contiguous areas will fail.
通过 echo compact_memory可以手动触发内存整理。可以看到通过手动触发内存整理。4MB,2MB,1MB等大内存块的数量都有了明显的增加。
# cat /proc/buddyinfo
Node 0, zone Normal 85 161 37 594 862 267 54 22 8 8 88
# echo 1 > /proc/sys/vm/compact_memory
# cat /proc/buddyinfo
Node 0, zone Normal 135 283 101 163 122 107 72 54 21 16 95
后续
上面我们描述了查看内存分布情况 和 通过vmtouch和 drop_caches 等工具手动调节内存中缓存的方式,以及手动触发内存碎片整理的机制。那么内核回收cached的机制具体而言是什么样的呢?。这个待后续系统了解linux的内存管理子系统之后再做介绍。关于内核对内存的回收机制
参考:
meminfo:
https://lynxbee.com/understanding-proc-meminfo-analyzing-linux-memory-utilization/#.Y8i4nxVBxPY
anon-pages:
https://unix.stackexchange.com/questions/677006/what-is-anon-pages-in-memory
overcommit:
https://zhuanlan.zhihu.com/p/461093695
vmtouch:
https://www.cnblogs.com/coldplayerest/archive/2012/02/28/2371881.html
https://github.com/hoytech/vmtouch/blob/master/vmtouch.pod