深入理解Linux内存free命令

服务器的内存条装的是 16GB, 里面跑了好几个服务程序, 执行了 free 带 -h 参数的命令以后一看, 显示出来的空闲存储空间只剩下 1GB。空闲的这些内存空间变少这一回事, 并不代表着整个系统在内存这一块是缺乏的情况。

正在被程序运行的时候所使用的数据, 还有文件内容在里面的缓冲部分, 再就是磁盘块的缓冲部分, 这些都有可能去占用那种叫做随机存取存储器的东西。它们各自存在的用途是完全不相同的, 所以说, 要去释放掉这部分内存资源的时候, 所依据的判断条件也是完全不同的那个样子。

我们把匿名内存和Page Cache分开来拆开揉碎去讲, 然后再转回到free这个环节去看一看这些具体的数字到底是多少。

所谓的匿名内存, 指的就是程序当前正在使用的那部分数据。

所谓的匿名内存, 它并没有普通的文件充当后备存储。进程里的堆、栈, 还有通过匿名 mmap() 这种调用方式产生的映射区域, 这些都是非常常见的来源。

在服务所处理的对象、数据处理环节所产生的数组, 以及程序正在执行时候的暂时性结果这些地方, 通常都要去使用这种类型的内存, 在这里进行探讨的内容是针对主机里面的随机存取存储器, 至于显卡所使用的显存, 还需要去单独查看相关信息。

你可以参考下面这些由C语言编写的示例代码, 以此来加深理解。

你所得到的那个空间, 它不一定立马就对应上了同等大小的新的物理内存。当你对那些还没有搞到实际物理页的匿名映射去写数据的时候, 内核会在那个时候按照需求去分配页面。你这边程序申请了多少内容, 和你那边实际上住了多少内容, 这两个事情需要分开来各自去观察。

这些运行的时候产生的数据, 是没有那种普通的、能够被再读取一遍的文件副本存在的, 也就是说没有地方可以拿来直接再读数据的普通文件拷贝这个东西。内核如果想要把这些内容给保留下来, 那么它就不可以随随便便就丢掉不管的, 必须得好好留着才行。

存在可用的交换空间这种情况, 而且页面的内容又允许进行交换操作这样的话, 有一部分那个叫做匿名页的东西是可以被换出到那个交换空间里面去的。程序如果执行了释放内存这个动作的话, 也能让那些相关的空间得到复用或者是被归还给系统去用的, 至于具体是怎么个情况, 那就得看那个内存分配器具体是如何处理的了。

匿名内存是用来放程序运行的数据的, 所以我们看它变多变少的时候, 得看着进程在内存里待着的情况, 还有业务忙不忙, 以及交换活动干啥呢, 这种种情况加一块儿来判断, 不能直接就拿文件缓存那种回收的方式硬套着用去, 你可以去看看那个内核对于匿名内存是怎么说明的。

2 Page Cache是把文件内容留在内存里面。

普通地采取缓冲读取这种方式的时候, 它通常都会去使用Page Cache这个东西, 等到出现缓存没有命中的时候, 内核就会亲自从存储设备那一边把文件数据读出来, 并且把它放进去内存里面待着, 再次进行访问的时候呢, 那些仍然还在缓存里面的内容就可以直接被使用到, 这样也就减少了磁盘I/O操作。

先去弄一个已经在那的大文件, 然后接着对那个大文件连续进行读取这个动作, 要把它读取两回:

重定向到 /dev/null 可以减少终端显示对耗时的干扰。文件能被内存容纳、缓存没有被回收时,第二次读取往往更快。文件原先已被缓存,两次差距也可能很小。

当我们加载那些模型的权重, 或者是去扫描训练数据, 再或者启动相应的那个程序, 这些操作在某种程度上可能都会受益于那个文件缓存机制。

即使是对于普通的文件而言, 其 mmap() 这个调用过程通常也会使用到页缓存这一功能;而如果在出现了私有映射之后并且发生了写时复制的情况, 那么经过修改的那些页面有可能就会转变为匿名页的类型。当然, 还有其他的某些访问方式存在的可能性, 它们是可以用来绕过页缓存的。

关于这方面的详情与说明内容, 您可以参见内核中相关的 Page Cache 文档资料部分。

写文件的操作也是会用到 Page Cache 的。通常那种缓冲写入的办法, 是先把缓存给改一下, 然后把相应的页面弄成脏的数据状态, 最后再让内核去安排实际的写回操作。

页面状态

内存与文件的关系

回收条件

Clean,干净页

内容是和文件保持一致的情况。

这种数据在一般情况下是可以被丢弃的, 等到后续需要再次访问的时候再进行重新读取操作。

那些被称为Dirty的页面, 其实就是脏页。

修改尚未完成写回

一般情况下, 是需要先一步把写回这个动作给完成掉的。

write()这个函数调用成功返回出来以后, 它并不保证数据一定已经持久化保存到存储介质里去了。

那些需要对持久化语义进行明确规定的程序设计场景里面, 必须正确地使用fsync()以及同步写入等机制来进行数据的强制落盘操作, 并且还要对其中可能出现的错误情况进行妥善处理与响应。对于相关的详情信息大家可以去参见关于write()的手册页面。

Page Cache这个服务, 是用来进行文件的读取和写入操作的。一般情况下, 干净的文件页是比较容易回收的, 可是脏页就要考虑把它写回磁盘所带来的成本问题。当缓存变得越来越大时候, 往往就意味着内存正在减少对磁盘进行访问的情况出现。

第三点, 也就是关于那些面向磁盘块的缓存机制。

在 free 中的这个位置, 对应的是 /proc/ 里面的那个项, 主要是用来表示原始磁盘块的临时缓存。

Page Cache, 这个术语它关注的是文件本身所包含的那些内容部分, 所以说它更加接近于对块设备进行访问的这种操作情况。就比如说吧, 在有一些具体的文件系统场景当中, 它们去读取像是块位图这种存在磁盘上面的元数据块的时候, 往往会使用相关的一些块缓冲机制。

由此可见, 这两者之间实际上只是代表了人们用来理解具体用途视角的不同而已, 这并不能意味着说它们是两个完全独立的物理内存池子。

不要把它简单地当成是去写缓存, Page Cache 这一块的功能也不仅仅是用来进行数据读取的操作, 两边的系统都可能会牵扯到数据的写入、读出, 还有关于那些脏掉的数据该怎么去处理的这一类事情。

所涉及到的那些资料, 它里面还会去讲到关于块的位置、状态等等这些管理信息方面的一些情况。那个用来描述块的这样一个结构, 它是没办法把这个东西和相关的统计值直接画等号的。有关的那些具体机制, 请你去看一看内核里面的Heads文档。

还有一类内容是容易导致人们产生混淆情形的, 那就是内核缓存里面的 inode 这些对象它们通常是由 Slab 来进行管理的, 那些可以被回收的部分会被计入到某个统计项中的, 这个具体的统计含义这里没有写出来但它是存在的, 所以用户在进行理解的时候需要把它们和存储在磁盘上面的元数据块缓存给区分开, 不要弄混了这两者之间的关系。

想把缓冲和缓存分开看,可以执行:

参数会开启显示模式, 这个操作把数据区和缓存区这两个部分拆分成两列来进行排列, 这样的安排方便人们去分别查看它们各自所占用的情况。

这个概念主要是关于磁盘块临时缓存内容的反映。它并不等同于文件系统元数据的总和, 同时也不能直接被视为写缓存的一种形式。当需要对内存压力状况进行判断的时候, 必须综合考虑页缓存、Slab对象分配情况以及系统可用内存的整体数据, 这样才能得到一个相对准确的结果。

4、把情况重新回到那个免费的层面,也就是要把分类去对应到数字上面这回事上来。

把那个步骤率先进行。

这里有一组数据, 这些数据的目的是为了帮助大家更容易去理解。

字段

含义

阅读重点

total

系统里面能够拿来做事情的那个物理内存, 它的总量是多少。

有一部分内存是被保留下来的, 这部分不被计算在内。

used

已使用或不可用的内存

它并不等同于匿名内存的概念, 而且也不是各个进程所占用的资源数量加在一起得到的总和。

free

现在这个阶段, 内存处于完全没有使用的状态。

那些还在缓存里面被占用着的那些内存, 它是不包含在内的。

主要是 tmpfs、共享内存等占用

与其他的那些列之间存在一定的重叠情况。

buff/cache

、 和 的合计

并不是所有的事物都能够被立刻地释放出来。

无需交换即可供新应用使用的内存估计

优先观察这个余量

现在这个 -ng 的 used, 是按 total 减去 free 之后再算出来的结果, 一些旧版本会扣除那部分 free 以及缓存数据, 各列之间不能随意相加, 大家得去参见那个 free 的官方手册。

这一点并不是简单的等于 free 加上 buff 和 cache。这个估算过程会考虑到那些可以被回收的页面、系统当前的内存水位线, 以及系统为了正常运行而必须保留下来的内存量。

此外, 它里面还包含了由 tmpfs 文件系统产生的页内存以及共享内存相关的页面数据。因此, 人们是绝对不能把这一整列的数据都看作是普通的磁盘文件副本从而随意丢弃掉去释放内存空间的。如果大家想要了解更详细的信息的话, 可以去查阅内核内存统计文档的相关内容。

比如说, 完全空闲的内存就只有那 3GB 这么多了。这时候程序还需要使用 6GB。在这样的情况下。系统是可以去回收足够的文件缓存的。它这么做可以腾出一定的空间来。如果申请速度超过了后台回收能力的时候。任务可能是会参与到直接回收这个环节里面去的。服务的延迟也就会跟着增加了。

关于要不要进行扩容工作, 除了别的情况之外, 还需要去考察服务的整体表现情况。

在缓存增长到一定程度之后, 它保持着一个稳定的状态, 并且交换活动很少, 而服务的延迟也处于正常的水平情况, 这种情况通常符合文件缓存正在发挥作用的一种表现特征。

情况一直在变差, 与此同时, 交换活动增多, 业务延迟也变大, 这时候就必须去查看进程数量的增长状况、任务并发执行的情况以及内存的限制设置, 容器方面还需要去检查它自己的限额指标, 主机上面如果还有剩余空间并不一定能说明容器内部也有足够的剩余资源可供使用, 具体的内容请参考内存控制的详细说明部分。

不需要为了使得 free 对应的数值变大就去频繁地对缓存进行清理的操作。这种操作会导致系统必须重新地读取文件的内容, 并且还要重新构建缓存, 进而会增加 I/O 开销以及 CPU 方面的消耗。具体的说明内容可以参见内核部分所提到的相关事项。

相关推荐
creator_Li1 个月前
Linux 的 Page Cache
linux·page cache
赖small强1 年前
【Linux 内存管理】深入解析Linux缓存行(Cache Line)与内存不对齐引发的Bus Error硬件异常
内存对齐·linux内存管理·cache line·bus error
赖small强1 年前
【Linux 内存管理】zram 技术详解与实战指南
linux内存管理·swap·zram
SuperHeroWu71 年前
鸿蒙应用如何实现内存级别全局缓存数据?
华为·harmonyos·单例·lrucache·appstroage·内存缓存
紫郢剑侠2 年前
Linux shell编程学习笔记63:free命令 获取内存使用信息
linux·学习笔记·内存管理·free命令·内存使用信息
董哥聊技术3 年前
Linux内存管理 | 一、内存管理的由来及思想
内存管理·linux内存管理·linux驱动开发
卍一十二画卍3 年前
Linux内存管理 | 二、虚拟地址空间布局
linux·mmu·内存管理·linux内存管理·linux驱动开发
卍一十二画卍3 年前
Linux内存管理 | 一、内存管理的由来及思想
linux·内存管理·操作系统内存管理·linux内存管理·linux内核开发