Linux的缓存内存(cache memory)

2023-11-18

PS:为什么Linux系统没运行多少程序,显示的可用内存这么少?其实Linux与Win的内存管理不同,会尽量缓存内存以提高读写性能,通常叫做Cache Memory。

为什么Linux系统没运行多少程序,显示的可用内存这么少?其实Linux与Win的内存管理不同,会尽量缓存内存以提高读写性能,通常叫做Cache Memory。

有时候你会发现没有什么程序在运行,但是使用top或free命令看到可用内存free项会很少,此时查看系统的 /proc/meminfo 文件,会发现有一项 Cached Memory:
输入cat /proc/meminfo查看:

MemTotal: 16425996 kB
    MemFree: 5698808 kB
    Buffers: 380904 kB
    Cached: 9389356 kB
    SwapCached: 212 kB
    Active: 6569200 kB
    Inactive: 3725364 kB
    HighTotal: 0 kB
    HighFree: 0 kB
    LowTotal: 16425996 kB
    LowFree: 5698808 kB
    SwapTotal: 8273464 kB
    SwapFree: 8273252 kB
    Dirty: 980 kB
    Writeback: 0 kB
    AnonPages: 524108 kB
    Mapped: 24568 kB
    Slab: 381776 kB
    PageTables: 7496 kB
    NFS_Unstable: 0 kB
    Bounce: 0 kB
    CommitLimit: 16486460 kB
    Committed_AS: 2143856 kB
    VmallocTotal: 34359738367 kB
    VmallocUsed: 267656 kB
    VmallocChunk: 34359469303 kB
    HugePages_Total: 0
    HugePages_Free: 0
    HugePages_Rsvd: 0
    Hugepagesize: 2048 kB

free命令里各项内存指标说明:

total used free shared buffers cached
Mem: 16425996 10727220 5698776 0 380904 9389832
-/+ buffers/cache: 956484 15469512
Swap: 8273464 212 8273252

其中第一行用全局角度描述系统使用的内存状况:
total——总物理内存
used——已使用内存,一般情况这个值会比较大,因为这个值包括了cache+应用程序使用的内存
free——完全未被使用的内存
shared——应用程序共享内存
buffers——缓存,主要用于目录方面,inode值等(ls大目录可看到这个值增加)
cached——缓存,用于已打开的文件
总结:
total=used+free
used=buffers+cached (maybe add shared also)

第二行描述应用程序的内存使用:
前个值表示-buffers/cache——应用程序使用的内存大小,used减去缓存值
后个值表示+buffers/cache——所有可供应用程序使用的内存大小,free加上缓存值
总结:
-buffers/cache=used-buffers-cached
+buffers/cache=free+buffers+cached

第三行表示swap的使用:
used——已使用
free——未使用

什么是Cache Memory(缓存内存):

当你读写文件的时候,Linux内核为了提高读写性能与速度,会将文件在内存中进行缓存,这部分内存就是Cache Memory(缓存内存)。即使你的程序运行结束后,Cache Memory也不会自动释放。这就会导致你在Linux系统中程序频繁读写文件后,你会发现可用物理内存会很少。

其实这缓存内存(Cache Memory)在你需要使用内存的时候会自动释放,所以你不必担心没有内存可用。如果你希望手动去释放Cache Memory也是有办法的。

如何释放Cache Memory(缓存内存):

用下面的命令可以释放Cache Memory:

To free pagecache:
echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes:
echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:
echo 3 > /proc/sys/vm/drop_caches

注意,释放前最好sync一下,防止丢失数据。

总结:个人经验认为没必要手动释放,这种内存管理方式也是比win优胜的地方之一!因为Linux的内核内存管理机制,一般情况下不需要特意去释放已经使用的cache。这些cache起来的内容可以提高文件以及磁盘的读写速度。

页面缓存——内存与文件的那些事儿

提到文件,操作系统必须解决两个重要的问题。首先是硬盘驱动器的存取速度缓慢得令人头疼(相对于内存而言),尤其是磁盘的寻道性能。第二个是要满足‘一次性加载文件内容到物理内存并在程序间共享’的需求。如果你使用进程浏览器翻看Windows进程,就会发现大约15MB的共享DLL被加载进了每一个进程。我目前的Windows系统就运行了100个进程,如果没有共享机制,那将消耗大约1.5GB的物理内存仅仅用于存放公用DLL。这可不怎么好。同样的,几乎所有的Linux程序都需要ld.so和libc,以及其它的公用函数库。

令人愉快的是,这两个问题可以被一石二鸟的解决:页面缓存(page cache),内核用它保存与页面同等大小的文件数据块。为了展示页面缓存,我需要祭出一个名叫render的Linux程序,它会打开一个scene.dat文件,每次读取其中的512字节,并将这些内容保存到一个建立在堆上的内存块中。首次的读取是这样的:


这看起来很简单,但还有很多事情会发生。首先,即使这个程序只调用了常规的read函数,此时也会有三个 4KB的页帧存储在页面缓存当中,它们持有scene.dat的一部分数据。尽管有时这令人惊讶,但的确所有的常规文件I/O都是通过页面缓存来进行的。在x86 Linux里,内核将文件看作是4KB大小的数据块的序列。即使你只从文件读取一个字节,包含此字节的整个4KB数据块都会被读取,并放入到页面缓存当中。这样做是有道理的,因为磁盘的持续性数据吞吐量很不错,而且一般说来,程序对于文件中某区域的读取都不止几个字节。页面缓存知道每一个4KB数据块在文件中的对应位置,如上图所示的#0, #1等等。与Linux的页面缓存类似,Windows使用256KB的views。

不幸的是,在一个普通的文件读取操作中,内核必须复制页面缓存的内容到一个用户缓冲区中,这不仅消耗CPU时间,伤害了CPU cache的性能,还因为存储了重复信息而浪费物理内存。如上面每张图所示,scene.dat的内容被保存了两遍,而且程序的每个实例都会保存一份。至此,我们缓和了磁盘延迟的问题,但却在其余的每个问题上惨败。内存映射文件(memory-mapped files)将引领我们走出混乱:

当你使用文件映射的时候,内核将你的程序的虚拟内存页直接映射到页面缓存上。这将导致一个显著的性能提升:《Windows系统编程》指出常规的文件读取操作运行时性能改善30%以上;《Unix环境高级编程》指出类似的情况也发生在Linux和Solaris系统上。你还可能因此而节省下大量的物理内存,这依赖于你的程序的具体情况。

 

和以前一样,提到性能,实际测量才是王道,但是内存映射的确值得被程序员们放入工具箱。相关的API也很漂亮,它提供了像访问内存中的字节一样的方式来访问一个文件,不需要你多操心,也不牺牲代码的可读性。回忆一下地址空间、还有那个在Unix类系统上关于mmap的实验,Windows下的CreateFileMapping及其在高级语言中的各种可用封装。当你映射一个文件时,它的内容并不是立刻就被全部放入内存的,而是依赖页故障(page fault)按需读取。在获取了一个包含所需的文件数据的页帧后,对应的故障处理函数会将你的虚拟内存页映射到页面缓存上。如果所需内容不在缓存当中,此过程还将包含磁盘I/O操作。

现在给你出一个流行的测试题。想象一下,在最后一个render程序的实例退出之时,那些保存了scene.dat的页面缓存会被立刻清理吗?人们通常会这样认为,但这是个坏主意。如果你仔细想想,我们经常会在一个程序中创建一个文件,退出,紧接着在第二个程序中使用这个文件。页面缓存必须能处理此类情况。如果你再多想想,内核何必总是要舍弃页面缓存中的内容呢?记住,磁盘比RAM慢5个数量级,因此一个页面缓存的命中(hit)就意味着巨大的胜利。只要还有足够的空闲物理内存,缓存就应该尽可能保持满状态。所以它与特定的进程并不相关,而是一个系统级的资源。如果你一周前运行过render,而此时scene.dat还在缓存当中,那真令人高兴。这就是为什么内核缓存的大小会稳步增加,直到缓存上限。这并非因为操作系统是破烂货,吞噬你的RAM,事实上这是种好的行为,反而释放物理内存才是一种浪费。缓存要利用得越充分越好。

由于使用了页面缓存体系结构,当一个程序调用write()时,相关的字节被简单的复制到页面缓存中,并且将页面标记为脏的(dirty)。磁盘I/O一般不会立刻发生,因此你的程序的执行不会被打断去等待磁盘设备。这样做的缺点是,如果此时计算机死机,那么你写入的数据将不会被记录下来。因此重要的文件,比如数据库事务记录必须被fsync() (但是还要小心磁盘控制器的缓存)。另一方面,读取操作一般会打断你的程序直到准备好所需的数据。内核通常采用积极加载(eager loading)的方式来缓解这个问题。以提前读取(read ahead)为例,内核会预先加载一些页到页面缓存,并期待你的读取操作。通过提示系统即将对文件进行的是顺序还是随机读取操作(参看madvise(), readahead(), Windows缓存提示),你可以帮助内核调整它的积极加载行为。Linux的确会对内存映射文件进行预取,但我不太确定Windows是否也如此。最后需要一提的是,你还可以通过在Linux中使用O_DIRECT或在Windows中使用NO_BUFFERING来绕过页面缓存,有些数据库软件就是这么做的。

一个文件映射可以是私有的(private)或共享的(shared)。这里的区别只有在更改(update)内存中的内容时才会显现出来:在私有映射中,更改并不会被提交到磁盘或对其他进程可见,而这在共享的映射中就会发生。内核使用写时拷贝(copy on write)技术,通过页表项(page table entries),实现私有映射。在下面的例子中,render和另一个叫render3d的程序(我是不是很有创意?)同时私有映射了scene.dat。随后render改写了映射到此文件的虚拟内存区域:

上图所示的只读的页表项并不意味着映射是只读的,它们只是内核耍的小把戏,用于共享物理内存直到可能的最后一刻。你会发现‘私有’一词是多么的不恰当,你只需记住它只在数据发生更改时起作用。此设计所带来的一个结果就是,一个以私有方式映射文件的虚拟内存页可以观察到其他进程对此文件的改动,只要之前对这个内存页进行的都是读取操作。一旦发生过写时拷贝,就不会再观察到其他进程对此文件的改动了。此行为不是内核提供的,而是在x86系统上就会如此。另外,从API的角度来说,这也是合理的。与此相反,共享映射只是简单的映射到页面缓存,仅此而已。对页面的所有更改操作对其他进程都可见,而且最终会执行磁盘操作。最后,如果此共享映射是只读的,那么页故障将触发段错误(segmentation fault)而不是写时拷贝。

 

被动态加载的函数库通过文件映射机制放入到你的程序的地址空间中。这里没有任何特别之处,同样是采用私有文件映射,跟提供给你调用的常规API别无二致。下面的例子展示了两个运行中的render程序的一部分地址空间,还有物理内存。它将我们之前看到的概念都联系在了一起。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux的缓存内存(cache memory) 的相关文章

随机推荐

  • Stm32旧版库函数3——nrf24l01 16位数据 51单片机发送与stm32接收

    51代码 include
  • WAP调用微信支付https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_1

    必看 要用WAP版的微信支付 首先你得有腾讯公司的邀请资格 要是没有 那么就不用往下看了 具体请咨询 0755 83768788 公司做的一个购物网站 之前微信版的网站要搬在webView上 可是微信支付是个问题 在外部浏览器怎么都发不起微
  • 802.11协议数据帧详解(一)——802.11帧结构与分类

    今天继续给大家介绍WLAN 本文主要内容是802 11帧格式 一 802 11数据帧整体结构 IEEE802 11系列标准定义了WLAN无线网络数据帧的帧结构 和基本的物理层 MAC层通信标准 与802 3定义的以太网数据帧格式及通信方式不
  • C++之继承<inheritance>

    目录 前言 继承 1 继承的概念与定义 1 1 继承的概念 1 2 继承的定义 2 基类和派生类对象赋值转换 3 继承中的作用域 4 派生类的默认成员函数 5 继承与友元 6 继承与静态成员 7 复杂的菱形继承及菱形虚拟继承 8 继承的总结
  • 前端响应式布局原理与实践

    前言 作为一个前端开发者 响应式网站开发是必备技能之一 响应式有它的很好的优点 也有它一定的缺点 这就需要我们在开发的时候做出取舍 对于内容较少 主要为展示类网站 故采用响应式 对于内容多 管理类的网站采用分开开发的方式 不同设备采用不同的
  • Ubuntu 16.04 设置pycharm 2018版本的 桌面快捷启动方式

    在ubuntu环境中每次使用pycharm需要到它的安装目录中执行 pycharm sh来启动pycharm 比较麻烦 那么如何设置快捷方式呢 首先Ubuntu下所有的快捷方式都在 usr share applications 解压 这里我
  • Dubbo启动错误

    加完Nacos配置后报错 信息 DUBBO The registry
  • 第十七篇:Unity/UE4如何实现Cave空间(一)

    首先什么叫CAVE空间 CAVE是围绕着观察者具有多个图像画面的虚拟现实系统 多个投影面组成一个虚拟空间 理论上CAVE是基于计算机图形学把高分辨率的立体投影技术和三维计算机图形技术 音响技术 传感器技术等综合在一起 产生一个供多人使用的完
  • css改变svg颜色_如何使用CSS混合模式和SVG动态更改产品图像的颜色

    css改变svg颜色 To better explain that title right off the bat here s what we re about to learn and it s easier than you thin
  • 《算法设计与分析》学习笔记

    目录 算法基本概念 算法的定义 算法复杂度分析 渐近记号 渐近上界记号O 渐近下界记号 渐近紧确界记号 非渐近紧确上界记号o 非渐近紧确下界记号 渐进记号极限定义 分治 分治步骤 递归树 编辑代入法 主方法 改变变量 二叉树 堆 建堆 堆排
  • C语言 基础知识之static(static是什么,static的好处,static的使用和作用)

    一 static是什么 static是C C 中的修饰符 可以用来修饰变量 也可以用来修饰函数 二 static的好处是什么 1 隐藏变量或函数 隔离错误 有利于模块化程序 在编程中 难免会用到全局变量 全局变量的作用域是整个源程序 当一个
  • virtualbox虚拟机安装Ubuntu异常处理:FATAL: NO bootable medium found! System halted

    遇到的问题 当virtualbox虚拟机安装linux系统 异常处理 FATAL NO bootable medium found System halted 问题的原因 没有找到iso文件来安装系统 解决的方案 下载镜像文件 centos
  • InnoDB Rollback Segment & Undo Page Deallocation实现源码分析

    InnoDB Rollback Segment Undo Page Deallocation实现源码分析 4月 23rd 2012 发表评论 Trackback 1 InnoDB Rollback Segment 1 1 1 Rollbac
  • 计算机视觉人脸检测与识别

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 TOC 文章目录 使用opencv进行人脸检测 文件目录 二 init文件内容 shishi文件内容 coding utf 8 加载训练数据集文件 准备识别的图片
  • 基于微信小程序的短视频管理系统

    末尾获取源码 开发语言 Java Java开发工具 JDK1 8 后端框架 SSM 前端框架 VUE 数据库 MySQL5 7 服务器 Tomcat8 5 开发软件 IDEA Eclipse 是否Maven项目 是 目录 一 项目简介 二
  • NEZUKO: 1——202201152003

    NEZUKO 1 202201152003 About Release Back to the Top Name nezuko 1 Date release 21 Aug 2019 Author yunaranyancat Series n
  • 五一假期出行的数据爬取和分析

    出来旅行 用手机编辑的 代码格式有可能出现问题 等回去用电脑进行修改 你们的萧萧吖 随着旅游业的迅速发展 越来越多的人选择在假期去旅游 五一假期是国内最热门的旅游季节之一 吸引了大量的游客前往各个景点 本篇博客将介绍如何使用 Python
  • XXE漏洞原理

    XXE漏洞是XML外部实体注入漏洞 那什么是外部实体呢 XML DTD 1 文档类型定义 DTD 可定义合法的XML文档构建模块 它使用一系列合法的元素来定义文档的结构 2 DTD 可被成行地声明于 XML 文档中 也可作为一个外部引用 P
  • 机器学习基础 第三章 分类算法

    1 线性分类器 感知器 1 1 感知器 有如图1 1所示的两类数据希望找到 如果想把他们分开 最简单的方法就是用图中的绿线将它们分开 显然绿线的方程为 t 0 1x 1y 1 1 1 t omega 0 omega 1 x omega 1
  • Linux的缓存内存(cache memory)

    PS 为什么Linux系统没运行多少程序 显示的可用内存这么少 其实Linux与Win的内存管理不同 会尽量缓存内存以提高读写性能 通常叫做Cache Memory 为什么Linux系统没运行多少程序 显示的可用内存这么少 其实Linux与