【Linux】Linux Page Cache页面缓存的原理

Page cache(页面缓存)是计算机操作系统中的一种机制,用于将频繁访问的数据从磁盘存储到内存中,以便更快地访问。当程序从磁盘请求数据时,操作系统会检查该数据是否已经存在于页面缓存中。如果存在,数据可以直接从内存中获取,这比从磁盘访问要快得多。如果数据不在页面缓存中,它将从磁盘中获取并存储在缓存中供将来使用。

既然Page Cache是一种缓存,那么缓存必然带来以下问题:

  1. 占用内存多大空间?
  2. 内存空间满了怎么办,淘汰策略?
  3. 内存中的数据何时写入磁盘?
  4. 数据如何持久化、一致性如何保障?
  5. 内存中的数据是否会丢失?
  6. 持久化的触发时机?

page与Page Cache的关系

从磁盘中读取文件后写入Page Cache中,是将整个文件都写入呢,还是只写用到的那一部分?

page是内存管理分配的基本单位,Page Cache由多个page构成。page在操作系统中通常为4KB大小(32bits/64bits),而 Page Cache的大小则为4KB的整数倍。

操作系统为基于Page Cache的读缓存机制提供预读机制(PAGE_READAHEAD),例如用户线程仅仅请求读取磁盘上文件A的offset为0-3KB范围内的数据,由于磁盘的基本读写单位为block(4KB),于是操作系统至少会读0-4KB的内容,这恰好可以在一个page中装下。

但是操作系统出于局部性原理会选择将磁盘块offset[4KB,8KB)、[8KB,12KB)以及[12KB,16KB)都加载到内存,于是额外在内存中申请了3个page。

下面我们用一个例子来演示一下:

准备一个文本文件ooxx.txt,大小为,需大于4*4=16k:

$ ll ooxx.txt
-rw-rw-r-- 1 vagrant vagrant 41211 Dec 29 05:45 ooxx.txt

使用read命令读取ooxx.txt文件的第一行:

$ read a < ooxx.txt$ echo $a
bash

那么ooxx.txt前4页的内容将会被缓存在Page Cache中,我们可以使用hcache命令来查看查询文件或者目录有多少页被载入Page Cache中:

$ hcache ooxx.txt
+----------+----------------+------------+-----------+---------+
| Name     | Size (bytes)   | Pages      | Cached    | Percent |
|----------+----------------+------------+-----------+---------|
| ooxx.txt | 41211          | 11         | 4         | 036.364 |
+----------+----------------+------------+-----------+---------+

我们可以看到实际上内核使用readahead机制完成了16KB数据的读取,并放入了Page Cache中。

缺页中断

磁盘的数据怎么写入Page Cache?

操作系统以page为单位管理内存,当进程发现需要访问的数据不在内存时,操作系统可能会将数据以页的方式加载到内存中。上述过程被称为缺页中断,当操作系统发生缺页中断时,就会通过系统调用将page再次读到内存中。

缺页中断的作用

缺页中断是内存管理中的重要机制,具有以下重要作用:

  1. 页面调入内存:当应用程序访问的页面不在内存中时,缺页中断会触发操作系统将缺失的页面从磁盘加载到内存中。这样做的好处是,不需要将整个文件或数据集一次性全部加载到内存中,而是按需加载,只加载应用程序实际需要的页面。这样可以节省磁盘I/O开销,避免了无谓的磁盘读取操作,提高了系统的性能。

  2. 页面替换策略:当内存中的页面已满时,如果应用程序访问一个新的页面,操作系统需要选择一个页面进行替换,将其换出到磁盘上,为新的页面腾出空间。缺页中断提供了一个时机,让操作系统可以根据页面替换算法选择合适的页面进行替换,以保证内存中的页面是最有用的页面,提高内存的利用率。

  3. 延迟写策略:在写回策略下,当应用程序对一个脏页进行写操作时,脏页的写回操作不会立即进行,而是推迟到后续的某个时刻进行。这样可以将多次写操作合并为一次写操作,减少了磁盘写入的次数,降低了磁盘I/O开销。

  4. 页面预读取:为了进一步减少磁盘I/O开销,操作系统可以利用缺页中断的时机进行页面预读取。当应用程序访问一个页面时,操作系统可以预先加载一些相邻的页面到内存中,以提前满足应用程序的访问需求。这样可以减少后续的缺页中断和磁盘读取操作,提高了系统的响应速度。

  5. 权限检查和处理:缺页中断还可以用于检查应用程序对页面的访问权限。操作系统可以根据页面的访问权限(例如只读、读写等)来判断应用程序的访问是否合法,并根据需要进行相应的处理。

缺页中断的处理流程

当发生缺页中断时,操作系统会按照以下步骤来处理:

  1. 中断处理程序:当发生缺页中断时,CPU会暂停当前应用程序的执行,并跳转到操作系统的中断处理程序。这个中断处理程序负责处理缺页中断。

  2. 中断处理程序的执行:中断处理程序会首先保存当前应用程序的上下文信息,包括寄存器的值和程序计数器等。然后,它会根据缺页中断的原因进行相应的处理。

  3. 页面调入内存:如果缺页中断是由于应用程序访问的页面不在内存中引起的,操作系统会触发页面调入内存的过程。它会根据页面表中的信息,确定需要调入的页面的位置和大小,并从磁盘上读取相应的页面数据。

  4. 磁盘I/O操作:在页面调入内存的过程中,操作系统会进行磁盘I/O操作,将需要的页面数据从磁盘读取到内存中。这包括了磁盘寻道、读取数据和数据传输等操作。

  5. 更新页表:当页面数据成功加载到内存中后,操作系统会更新页表,将该页面的状态设置为已加载,并将页面的物理地址映射到对应的虚拟地址。

  6. 恢复上下文和重新执行应用程序:当页面调入内存完成后,中断处理程序会恢复之前保存的应用程序的上下文信息,并将控制权返回给应用程序。应用程序会继续执行之前被中断的指令,但这次访问的页面已经在内存中了,不会再触发缺页中断。

Page Cache的工作原理

Page Cache的工作原理如下:

  1. 当应用程序打开一个文件并读取其中的数据时,操作系统会将文件的内容读取到内存中,并将其缓存为一个或多个页(通常是4KB大小的页)。

  2. 这些缓存的页被存储在一个被称为Page Cache的内存区域中,它是内核管理的一部分。

  3. 当应用程序再次访问相同的文件时,操作系统首先检查Page Cache中是否存在这些页的副本。如果存在,操作系统会直接从Page Cache中返回数据,而不需要再次访问磁盘。

  4. 如果应用程序对文件进行写操作,数据会被写入到Page Cache中的脏页(dirty page)。脏页表示该页的内容已经被修改,但还没有写回到磁盘。

  5. 当系统内存压力较大或需要释放内存时,内核会触发缓存刷新(cache flushing)操作,将脏页从Page Cache写回到磁盘中。

Page Cache的回写策略

回写策略是为了确保缓存数据的一致性和避免数据丢失而设计的。当Page被标记为dirty时,表示该Page中的数据已经被修改过,这些数据需要被写回到磁盘上的,Linux提供了以下两种回写策略:

  • Write Through(写穿):向用户层提供特定接口,应用程序可主动调用接口来保证文件一致性;

  • Write back(写回):系统中存在定期任务(表现形式为内核线程),周期性地同步文件系统中文件脏数据块,这是默认的 Linux一致性方案;

Write Through写穿

Write Through(写透)是将数据写入Page Cache后,立即将数据写入磁盘设备。这样可以确保数据在发生故障或系统崩溃时不会丢失,因为数据已经被持久地写入磁盘。

在JAVA中使用如下的代码实现Write Through写穿:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;public class WriteThroughTest {public static void main(String[] args) throws IOException {File file = new File("/home/vagrant/testfileio/ooxx.txt");FileOutputStream out = new FileOutputStream(file);out.write("hello".getBytes(StandardCharsets.UTF_8));out.getFD().sync(); // 立即刷入磁盘}
}

我们可以使用strace命令追踪上面程序执行过程中产生的系统调用:

openat(AT_FDCWD, "/home/vagrant/testfileio/ooxx.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
write(4, "hello", 5)                    = 5
fsync(4)                                = 0
close(4)

可以系统调用中包含fsync,该命令会把文件描述符fd引用的文件修改过的元数据和数据立即写回到存储设备。

Write back写回

在Write Back模式下,写入操作只会将数据写入Page cache,并不立即写入磁盘设备。而是在后续的时间点或特定条件下,将脏页(已被修改但尚未写入磁盘)批量写回磁盘。

在JAVA中使用Write back写回只需要将上面例子中的立即刷入磁盘代码注释即可:

// out.getFD().sync()

这种回写策略下,数据的一致性完全依赖操作系统的自身机制,那么操作系统何时将Page Cache中的脏页数据写入磁盘中呢?

Page Cache写回时机

Linux内核提供了以下参数来优化Page Cache的性能和行为,我们可以通过这些参数来窥探Page Cache的写回时机。

$ sudo sysctl -a | grep "dirty"
vm.dirty_background_bytes = 0
vm.dirty_background_ratio = 10
vm.dirty_bytes = 0
vm.dirty_expire_centisecs = 3000
vm.dirty_ratio = 20
vm.dirty_writeback_centisecs = 500
vm.dirtytime_expire_seconds = 43200

具体参数说明:

  • vm.dirty_background_bytes:设置了系统内存中可以保持脏数据的最大字节数。当系统内存中的脏数据超过这个值时,Linux会开始触发后台刷新(异步刷新)将脏数据写入磁盘。

  • vm.dirty_background_ratio:设置了系统内存中可以保持脏数据的最大比例,默认为10%。

  • vm.dirty_bytes:设置了系统内存中允许累积的脏数据的最大字节数。当脏数据超过这个值时,Linux会触发前台刷新(同步刷新),直到将脏数据写入磁盘为止。

  • vm.dirty_ratio:设置了系统内存中允许累积的脏数据的最大比例,默认为20%。

  • vm.dirty_expire_centisecs:该参数指定了脏数据在内存中能够存活的时间,单位为百分之一秒。当脏数据在内存中超过这个时间后,系统会将其异步写入磁盘中,默认值为3000(30秒)。

  • vm.dirty_writeback_centisecs:表示系统在多长时间内进行一次脏数据的后台写回操作。它的单位是百分之一秒(centiseconds),默认值为500,即系统每5秒钟进行一次后台写回操作。

  • vm.dirtytime_expire_seconds:代表内存中脏数据的允许存储时间,单位为秒。当脏数据在内存中存储的时间超过这个时间,系统会将其写入磁盘,以释放内存。

跟pagecache相关的系统调用

内核提供了下面这些把Page Cache中内容写入磁盘的系统调用:

  • sync:将所有未写的系统缓冲区数据写入磁盘,不需要带任何参数。

  • syncfs:syncfs需要一个文件描述符,只将文件描述符指向的文件相关的文件系统的缓冲区数据写入磁盘。

  • fsync:将文件描述符fd引用的文件修改过的元数据和数据写入磁盘。

  • fdatasync:fdatasync函数类似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。

手动清除Page Cache

$ sync && echo 1 > /proc/sys/vm/drop_caches

表示先执行sync命令,将所有缓存数据写入磁盘中,然后将“1”写入到/proc/sys/vm/drop_caches文件中,表示清空页缓存。

$ sync && echo 2 > /proc/sys/vm/drop_caches

表示先执行sync命令,将所有缓存数据写入磁盘中,然后将“2”写入到/proc/sys/vm/drop_caches文件中,表示清空目录缓存和页缓存。

$ sync && echo 3 > /proc/sys/vm/drop_caches

表示先执行sync命令,将所有缓存数据写入磁盘中,然后将“3”写入到/proc/sys/vm/drop_caches文件中,表示清空目录缓存、页缓存和inode缓存。

hcache工具的使用

hcache是一个用于分析和显示Page Cache统计信息的命令行工具。它可以提供关于Page Cache的详细信息,包括脏页和干净页的数量、Page Cache的大小、缓存命中率等。

hcache是基于pcstat的,pcstat可以查看某个文件是否被缓存和根据进程pid来查看都缓存了哪些文件。hcache在其基础上增加了查看整个操作系统Cache和根据使用Cache大小排序的特性。

安装:

$ wget https://silenceshell-1255345740.cos.ap-shanghai.myqcloud.com/hcache$ chmod 755 hcache && mv hcache /usr/local/bin/

根据进程pid来查看都缓存了哪些文件

$ hcache -pid $$
+-----------------------------------------------------+----------------+------------+-----------+---------+
| Name                                                | Size (bytes)   | Pages      | Cached    | Percent |
|-----------------------------------------------------+----------------+------------+-----------+---------|
| /lib/x86_64-linux-gnu/libtinfo.so.5.9               | 170784         | 42         | 42        | 100.000 |
| /lib/x86_64-linux-gnu/ld-2.27.so                    | 179152         | 44         | 44        | 100.000 |
| /lib/x86_64-linux-gnu/libnss_compat-2.27.so         | 39744          | 10         | 10        | 100.000 |
| /lib/x86_64-linux-gnu/libnss_files-2.27.so          | 47568          | 12         | 12        | 100.000 |
| /lib/x86_64-linux-gnu/libnsl-2.27.so                | 97176          | 24         | 24        | 100.000 |
| /lib/x86_64-linux-gnu/libnss_nis-2.27.so            | 47576          | 12         | 12        | 100.000 |
| /usr/lib/locale/locale-archive                      | 3004224        | 734        | 734       | 100.000 |
| /lib/x86_64-linux-gnu/libc-2.27.so                  | 2030928        | 496        | 496       | 100.000 |
| /lib/x86_64-linux-gnu/libdl-2.27.so                 | 14560          | 4          | 4         | 100.000 |
| /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache | 26376          | 7          | 7         | 100.000 |
| /bin/bash                                           | 1113504        | 272        | 272       | 100.000 |
+-----------------------------------------------------+----------------+------------+-----------+---------+

hcache命令可以帮助您深入了解系统的Page Cache使用情况,以便进行性能分析和优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT上位机开发(动态库dll的开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 有的时候&#xff0c;我们不想把所有的代码都放在一个exe里面&#xff0c;这个时候我们就需要引入dll动态库的概念。在windows平台上面&#xff0c…

FlagData 2.0:全面、高效的大模型训练数据治理工具集

数据是大模型训练至关重要的一环。数据规模、质量、配比&#xff0c;很大程度上决定了最后大模型的性能表现。无论是大规模的预训练数据、精益求精的SFT数据都依托于一个完整的“获取-准备-处理-分析”数据流程。然而&#xff0c;当前的开源工具通常只专注于流程中的某一环节&a…

ThreeJs通过canvas和Sprite添加标签

在3D场景中很多时候会用到给模型添加标签&#xff0c;以表示这个模型的代号&#xff0c;尤其是大量重复模型的时候&#xff0c;添加标签是为了更直观的看到场景中每个模型的数据和名称&#xff0c;比如在仓库中有很多货架&#xff0c;就会需要查看每个货架的编号&#xff0c;如…

Flink Connector 开发

Flink Streaming Connector Flink是新一代流批统一的计算引擎&#xff0c;它需要从不同的第三方存储引擎中把数据读过来&#xff0c;进行处理&#xff0c;然后再写出到另外的存储引擎中。Connector的作用就相当于一个连接器&#xff0c;连接Flink计算引擎跟外界存储系统。Flin…

长亭牧云主机管理助手——免费轻量的服务器管理软件初体验

优点 安装十分简单&#xff0c;新手友好&#xff0c;一行命令搞定界面简洁&#xff0c;操作流畅无需公网 IP&#xff0c;可以面对复杂 NAT 环境进行救急可以统一管理大量主机&#xff0c;无需记住主机秘钥 地址 https://rivers.chaitin.cn/app/collie 安装 安装很简单&…

基于 listmonk 的电子邮件营销解决方案

背景 电子邮件营销&#xff08;EDM&#xff09;在广告、电商、供应链物流等行业应用广泛&#xff0c;亚马逊云科技的市场部门持续不断的收到客户反馈&#xff0c;希望可以提供简单便捷的方案。 亚马逊云科技产品体验链接&#xff1a;点击我立即体验 对于发送邮件的需求&…

深耕汽车检测设备领域,引领行业技术革新

在汽车工业飞速发展的今天&#xff0c;汽车检测技术作为保障车辆安全、提升维修效率的重要手段&#xff0c;日益受到行业内外的高度关注。康士柏汽车检测线设备厂家&#xff0c;作为这一领域的佼佼者&#xff0c;凭借其深厚的技术积累和卓越的产品品质&#xff0c;正引领着行业…

c# 学习笔记 - 委托(Delegate)

文章目录 1. 委托1.1 委托概述1.2 委托使用1.3 委托的传播 2. 匿名方法2.1 匿名方法概述2.2 匿名方法 1. 委托 1.1 委托概述 委托简介 委托就是对方法的引用&#xff0c;可以理解为例如整型变量的容器可以存储整形数据&#xff0c;委托就是某种方法的容器&#xff0c;可以用来…

数据库基础知识1

关系模型的程序员不需熟悉数据库的存取路径 在3层模式结构中,___I___是数据库的核心和关键,___Ⅱ___通常是模式的子集,数据库模式的描述提供给用户,____Ⅲ__的描述存储在硬盘上。Ⅰ.模式Ⅱ. 外模式Ⅲ. 内模式 数据库中,数据的物理独立性是指用户的应用程序与存储在磁盘上数据库…

D6208双向直流马达驱动芯片 用于IPC产品,可兼容BA6208,噪声低 ,工作电源电压范围宽。

D6208 是一块单片双向马达驱动电路&#xff0c;它使用TTL电平的逻辑信号就能控制卡式录音机和其它电子设备中的双向马达。该电路由一个逻辑部分和一个功率输出部分组成。逻辑部分控制马达正、反转向及制动&#xff0c;功率输出部分根据逻辑控制能提供100mA&#xff08;典型值&a…

迅腾文化观察:从“占位”到“心智”,从“借势”到“锁定”—— 高增长市场的企业战略之道

迅腾文化观察&#xff1a;从“占位”到“心智”&#xff0c;从“借势”到“锁定”—— 高增长市场的企业战略之道 在当今世界&#xff0c;市场环境瞬息万变&#xff0c;企业若想在激烈的市场竞争中立足并持续发展&#xff0c;必须不断地调整和优化自身的战略。在迅腾文化观察中…

electron进程通信之预加载脚本和渲染进程对主进程通信

主进程和预加载脚本通信 主进程 mian,js 和预加载脚本preload.js,在主进程中创建预加载脚本, const createWindow () > {// Create the browser window.const mainWindow new BrowserWindow({width: 300,height: 300,// 指定预加载脚本webPreferences: {preload: path.j…

web3 : blockscout剖析

Blockscout 是第一个功能齐全的开源区块链浏览器,可供任何以太坊虚拟机 (EVM) 链使用。项目方可以下载并使用Blockscout作为其链的浏览器,用户可以轻松验证交易、余额、区块确认、智能合约和其他记录。 目录 Blockscout可以做什么主要特征blockscoutDocker容器组件Postgres 1…

队列的数据结构实验报告

实验目的&#xff1a; 1、理解队列数据结构的概念和特点。 2、熟悉队列的应用场景和算法实现。 二、实验内容&#xff08;实验题目与说明&#xff09; 实现了一个循环队列&#xff0c;具有功能&#xff1a; 初始化队列。判断队列是否为空。判断队列是否已满。入队。出队。…

CSS基本知识

文章目录 1. CSS 是什么2. 基本语法规范3. 引入方式3.1 内部样式表3.2 行内样式表3.3 外部样式 4. 选择器4.1 选择器的功能4.2 选择器的种类4.3 基础选择器4.3.1 标签选择器4.3.2 类选择器4.3.3 id 选择器4.3.4 通配符选择器 4.4 复合选择器4.4.1 后代选择器4.4.2 伪类选择器 5…

【fiddler】fiddler抓包工具的使用

前言&#xff1a;我们可以通过fiddler软件&#xff0c;捕获到http请求&#xff0c;并修改请求参数 修改返回内容 fiddler下载,官网如下图 启动fiddler软件,点击file 选择 Capture Traffic 修改入参 (我们以谷歌浏览器发起请求为例) 此时会出现一个向上的箭头&#xff0c;点击…

Linux第8步_USB设置

学习完设置“虚拟机的电源”后&#xff0c;接着学习通过鼠标点击操作U盘&#xff0c;目的是了解USB设置。 1、在桌面&#xff0c;双击“VMware Workstation Pro”图标&#xff0c;得到下图&#xff1a; 2、点击“编辑虚拟机”&#xff0c;得到下图&#xff1a; 只要点击编辑虚…

Rockchip平台双屏异显功能实现(基于Android13)

Rockchip平台双屏异显功能实现(基于Android13) 1. 异显实现方案 Rockchip SDK平台支持两种不同的异显方案&#xff1a;Android Presentation和Android Activity指定屏幕启动。 使用Android Presentation方案&#xff0c;需要在APP开发中调用相应接口以使指定视图&#xff08…

【软件测试】2024年准备中/高级测试岗技术面试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、软件测试基础知…