内核脏页刷新到磁盘

 Sun, 19-Apr-2026 19:57:56
在 Linux 下,你要看的其实是内核脏页刷新到磁盘的策略,也就是系统多久会自动把内存里的脏数据刷回磁盘。下面给你一套最实用、直接能用的查看方法。
 

 

一、查看当前系统脏页刷新参数(核心)

 
bash
 
运行
 
 
 
 
sysctl -a | grep dirty
 
 
重点看这几个:
 
 
简单理解:
 

 

 

二、实时查看当前脏页数量、是否正在刷盘

 
bash
 
运行
 
 
 
 
cat /proc/meminfo | grep -E 'Dirty|Writeback'
 
 
 
实时监控:
 
bash
 
运行
 
 
 
 
watch -n1 "cat /proc/meminfo | grep -E 'Dirty|Writeback'"
 
 

 

三、查看刷盘线程(pdflush /bdi writeback)

 
bash
 
运行
 
 
 
 
ps aux | grep flush
 
 
会看到类似:
 
plaintext
 
 
 
 
 
root      ..... [flush-253:0]
 
 
这就是负责后台自动落盘的内核线程。
 

 

四、查看磁盘实际写入间隔(iotop)

 
bash
 
运行
 
 
 
 
iotop -o
 
 
可以看到:
 
 

 

五、一句话总结你关心的 “落盘时间间隔”

 
Linux 默认自动落盘策略是:
 
  1. 每 5 秒检查一次脏数据
  2. 脏数据存活超过 30 秒 必须落盘
  3. 脏数据太多时会立即强制落盘
 
也就是说:
 
正常情况下,数据最多在内存里待 30 秒就一定会刷到磁盘。
 
 
 
 
 
#include <fstream>
#include <string>

/**
 * @brief 将字符串保存到文件
 * @param file_path 文件路径
 * @param content 要保存的字符串
 * @param is_append 是否追加写入(true=追加,false=覆盖)
 * @return 保存成功返回true,失败返回false
 */
bool saveStringToFile(const std::string& file_path, const std::string& content, bool is_append = false) {
    // 确定打开模式
    std::ios::openmode mode = is_append ? std::ios::app : std::ios::out;
    std::ofstream out_file(file_path, mode);

    if (!out_file.is_open()) return false;

    out_file << content;
    out_file.close();
    return true;
}

// 使用示例
int main() {
    // 覆盖写入
    saveStringToFile("demo.txt", "第一行内容\n第二行内容", false);
    // 追加写入
    saveStringToFile("demo.txt", "\n追加的内容", true);
    return 0;
}
 
 

总结

 
  1. 文本文件用 std::ofstream + << 运算符,最简单通用;
  2. 二进制文件用 write() 方法;
  3. 记得检查文件是否打开成功,避免程序异常;
  4. 封装成工具函数,项目中可直接复用。
 
聊聊新话题
要及时落盘怎么办,调用fsync,如果fstream如何能获取到fd

C++ fstream 调用 fsync 落盘:获取文件描述符 (fd) 完整方案

 
你遇到的核心问题:标准 C++ fstream 没有直接暴露文件描述符 (fd),但要调用系统 fsync(int fd) 强制数据落盘,必须拿到 fd
 
我给你整理跨平台可用 + 平台原生的两种最稳妥方案,直接复制就能用。
 

 

核心原理

 
  1. fsync(fd)系统调用,必须依赖文件描述符(Linux/macOS)/ 文件句柄(Windows)
  2. C++ 标准未定义 fstream 获取 fd 的接口,但主流编译器都提供了扩展方法
  3. 先调用 ostream::flush() 刷新用户态缓冲区,再用 fsync 刷内核缓冲区,才能真正落盘
 

 

方案 1:跨平台通用(推荐,GCC/Clang/MSVC 全支持)

 

Linux/macOS (POSIX 系统)

 
basic_filebuf 提供 fd() 方法直接获取文件描述符:
 
cpp
 
运行
 
 
 
 
#include <fstream>
#include <unistd.h>  // fsync 头文件

bool syncToDisk(std::fstream& fs) {
    // 1. 先刷新C++流缓冲区到内核
    fs.flush();
    
    // 2. 获取文件描述符
    int fd = fs.rdbuf()->fd();
    if (fd == -1) return false;
    
    // 3. 调用fsync强制落盘
    return ::fsync(fd) == 0;
}
 
 

Windows 系统

 
Windows 用 _fileno + FlushFileBuffers 替代 fsync
 
cpp
 
运行
 
 
 
 
#include <fstream>
#include <windows.h>

bool syncToDisk(std::fstream& fs) {
    // 1. 刷新流缓冲区
    fs.flush();
    
    // 2. 获取文件句柄
    int fd = fs.rdbuf()->fd();
    HANDLE hFile = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
    if (hFile == INVALID_HANDLE_VALUE) return false;
    
    // 3. Windows强制落盘
    return FlushFileBuffers(hFile) != 0;
}
 
 

 

方案 2:封装成跨平台工具函数(直接用)

 
cpp
 
运行
 
 
 
 
#include <fstream>
#include <cstdlib>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

// 强制 fstream 数据写入磁盘(真正落盘,不丢数据)
bool fstream_fsync(std::fstream& file) {
    if (!file.is_open()) return false;

    // 第一步:刷新C++流缓冲区到操作系统内核
    file.flush();

    // 第二步:获取文件描述符
    int fd = file.rdbuf()->fd();
    if (fd < 0) return false;

    // 第三步:系统级强制落盘
#ifdef _WIN32
    HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
    return FlushFileBuffers(handle) != FALSE;
#else
    return ::fsync(fd) == 0;
#endif
}