在PC/服务器控制台下输入free -m输出如下:
caozilong@caozilong-Vostro-3268:~$ free -m
总计 已用 空闲 共享 缓冲/缓存 可用
内存: 7869 1389 4713 520 1766 5674
交换: 6808 0 6808
caozilong@caozilong-Vostro-3268:~$ free -m
总计 已用 空闲 共享 缓冲/缓存 可用
内存: 7869 1388 4706 528 1774 5666
交换: 6808 0 6808
caozilong@caozilong-Vostro-3268:~$ free -m
总计 已用 空闲 共享 缓冲/缓存 可用
内存: 7869 1389 4705 528 1774 5665
交换: 6808 0 6808
caozilong@caozilong-Vostro-3268:~$ free -m
总计 已用 空闲 共享 缓冲/缓存 可用
内存: 7869 1659 4263 565 1947 5355
交换: 6808 0 6808
caozilong@caozilong-Vostro-3268:~$
总计:表示内存总量,保持不变。
已用:表示已经在用的内存,这里包括用户程序使用的内存+系统缓存使用的内存。
空闲:空闲内存数量(真正的空闲,未被任何程序占用)
共享:多个进程共享的内存数量
缓冲/缓存:对应page cache/buffer cache的内存数量,这里面既有不能释放的,也有可以释放的。
可用:可以使用的内存数量,包括缓冲/缓存中可以释放的部分和空下内存两部分构成。
假设系统中的内存总量为M,其中内核占用S,用户私有空间占用UM,用户共享空间占用USM,空闲内存用FM表示。
按照道理,page cache/buffer cache是缓冲区,既然是缓冲区,那么没有也应该没有问题,缓冲/缓存不属于已用内存,所以应该算在可以释放的可用内存之列,所以按照道理:
可用内存=空闲内存+缓冲/缓存内存.
可是当我们按照这种方式计算是,发现不符合,以上面的为例:
5674(可用) < 4713 (空闲)+ 1766 (缓冲/缓存)= 6479
5666 (可用)< 4706(空闲) + 1774(缓冲/缓存) = 6480
5665 (可用) < 4705(空闲) + 1774(缓冲/缓存) = 6479
5355 (可用) < 4263(空闲) + 1947(缓冲/缓存) = 6210
原因就在于缓冲/缓存的部分包含不可释放的存储,不能全部算在可用里面,所以前面的公式不太对,应该修正为:
可用内存=空闲内存+缓冲/缓存中的可回收部分内存.
并且可以发现如下规律:
总计≈已用 +空闲 +缓冲/缓存
7869≈1389+4713 + 1766 = 7868
7869≈1388+4706 + 1774 = 7868
7869≈1389+4705 + 1774 = 7868
7869=1659+4263 + 1947 = 7869
至于这种不一致,目前猜测,page cache/buffer cache中,包含一部分可以释放的文件缓冲,还有一部分不能释放的缓冲,所以直接相加的话,会把不能释放的一部分也算在可用内存内,导致计算结果比实际值偏大,至于内核如何区分这两种page cache,待查。
free文档中已经明确给出来了,还推导个啥:
Used memory = total - free - buffers - cache;
为啥USED memory要这样计算,可能是因为USED内存和场景有关,从广义上说,所有的从BUDDY中分配的PAGE都是USED,但是这些分配出来的PAGE根据是否可回收,又有不同的特点,对于那些作为设备缓存和文件缓存的PAGE,因为有BACKEND存储,是可以回收的,所以这部分PAGE可以根据需要还回去,而对于另外一些PAGE,比如SLAB,和驱动中使用的PAGE,他们无法回收,是真正的USED:
实际上,不同的free版本(procps)计算方法有所不同,有些版本 used memory = total - available. 这相当于将buff/cache中不可释放部分统计到了USED中:
把BUFF/CACHE分开统计free -w
对公式进行演化:
总计≈已用 +空闲 +缓冲/缓存(可回收+不可回收)= 已用 +空闲 +缓冲/缓存(可回收)+缓冲/缓存(不可回收) = 已用 + 缓冲/缓存(不可回收)+ 空闲 +缓冲/缓存(可回收)= 不可用部分+可用部分。
继续演化:
缓冲/缓存 -(总计-可用-已用)+空闲 = 可用
其实就是上面公式的变形,只是这里从可用角度来分析,其中:
总计-可用-已用=缓冲/缓存中的不可回收部分
总计=可用+不可用
不可用部分=已用+缓冲/缓存中的不可回收部分
缓冲/缓存中包含两部分,可回收部分和不可回收部分
不可用部分包括已用和缓冲/缓存中的不可回收部分:
可用部分包括缓冲/缓存中的可回收部分和空闲部分,从缓冲/缓存减去不可以回收的那部分后,再加上空闲部分即是可用部分。
最终,总内存分为可用部分和不可用部分:
经过思考,怀疑这种区分(缓冲/缓存 中存在的不可释放部分)和PAGE页的状态FLAG有关,内核中有一个函数是buffer_busy(bh),所以缓冲/缓存中不可回收部分可能是脏BH数据,PIN数据以及被LOCK的buffer_head数据.这部分BH对应的PAGE是不可回收的。
所以,同样是缓冲区,但是加不加这些FLAG,会造成状态的不同,反映到FREE命令中,有的可以释放,有的不可以释放。
上图中,表示等式
Mem.total = Mem.used + Mem.free + Mem.(page/buffer) cache
缓冲中的不可用部分计算公式为:
缓冲/缓存中的不可用部分=Mem.free+Mem.buff/cache-Mem.avail = 3469860 + 2458400 - 5456168 = 472092
free -h -s 1命令会周期性的执行,按照比较友好的方式输出:
czl@czl-VirtualBox:~$ free -h -s 1
total used free shared buff/cache available
Mem: 981M 744M 66M 13M 169M 84M
Swap: 1.9G 437M 1.4G
total used free shared buff/cache available
Mem: 981M 745M 66M 13M 169M 84M
Swap: 1.9G 437M 1.4G
total used free shared buff/cache available
Mem: 981M 745M 66M 13M 169M 84M
Swap: 1.9G 437M 1.4G
total used free shared buff/cache available
Mem: 981M 745M 66M 13M 169M 84M
Swap: 1.9G 437M 1.4G
total used free shared buff/cache available
Mem: 981M 745M 66M 13M 169M 84M
Swap: 1.9G 437M 1.4G
^C
czl@czl-VirtualBox:~$
经过计算确认,符合
Mem.total = Mem.used + Mem.free + Mem.buff/cache
981M≈745M+66M+169M
from this equation view, we can clucude that:
Mem.buff/cache = shared + Mem.buf/cache(cant be freed) + Mem.buf/cache(can be freed).
shared + Mem.buf/cache(cant be freed) cant be freed, some of the cache buffer can be freed. so in this way:
可用内存 - (空闲内存+缓冲/缓存内存) = shared + Mem.buf/cache(cant be freed).
that will be resonable.
以上猜想在<<奔跑吧,Linux内核>>卷一中得到证实,在这本书中对各个成员的描述如下:
total:计算机中总的内存,这里有两种内存,一种是mem,一种是swap.前者是真实的物理内存,后者可以是某个磁盘文件,或者单个磁盘分区。
used:程序使用的内存大小.
free:未分配的物理内存大小.
shared:共享内存的大小,主要用于进程间通信.
buff/cache:buff指的是缓冲器,用于缓存输出到块设备的数据 buffer cache,而cache指的是page cache,用于缓存打开的文件,以提高访问文件的速度。
available:这是free命令新加的一个选项,当内存短缺时,系统可以回收buff和cache,那么avaiable = free + buff+ cache,这样做也不完全精确,因为在现在的linux内核中,不是所有的buffer和cache都可以回收,如共享内存段,tmpfs和ramfs等都属于不可回收的.所以这个公式应该变成:available = free + buff + cache - 不可回收的部分.
2024-01-15: 上面的总结可能有点问题,shared 不应该全部被算到Mem.buff/cache里面,因为除了文件共享,还有一些纯粹是进程之间BUFFER共享的部分。
2024-01-16:2024-01-15的总结不对,shared部分应该全部在mem.buf/cache里面,共享文件不可能是SHARED,SHARED的包含IPC的部分和匿名共享映射的部分,这部分都是可以交换出去的。
2024-01-16:在三思考后,经过测试:
1. 写一个应用不断malloc,之后memset触发页分配一段大内存,free查看,buff/cache没有变化,而used猛增,所以匿名页面占用的是used,不是buff/cache.
2.同样的方式测试匿名共享页面
ptr = map(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);memset(ptr, 0x5a, FILE_SIZE);
不断循环执行,发现此时的USED不变,但是BUFF/CACHE激增,所以SHARED是 BUFF/CACHE的一部分。
由于MAP_SHARED FLAG的匿名页面,用的vm_ops是shmem_vm_ops,其PAGE FAULT中是从SHMEM分配页面的,其调用路径上的关键函数shmem_add_to_page_cache:将分配的页面增加到了NR_FILE_PAGES和NR_SHMEM上面:
所以可以得到,SHARED的确实是BUFF/CACHE的一部分,不是USED的一部分,最早的说法更对。
3.实验3,将实验2的MAP 属性修改为MAP_PRIVATE | MAP_ANONYMOUS 在做测试,发现此时递增的不再是BUFF/CACHE,而是USED,这就和实验1,MALLOC的方式一样了。所以,匿名页面算在USED之内,SHARED页面算在BUFF/CACHE之内。
如何优化缓冲,缓存部分?
使用如下命令,命令会遍历所有文件系统中的超级块,将注册在超级块中的inode节点文件对应的page cache回刷到磁盘,释放page cache.
echo 3 > /proc/sys/vm/drop_caches
<