You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Process Monitor中WriteFile调用显示Paging I/O标记的原因及复现方法

Process Monitor中"Paging I/O"与"Synchronous Paging I/O"标记的成因及C++复现方法

成因解析

Process Monitor中的"Paging I/O"标记对应两种核心场景:

  • 直接操作系统分页文件:当WriteFile的目标是系统分页文件(pagefile.sys)时,会触发该标记——分页文件是Windows虚拟内存机制的核心载体,所有针对它的I/O都会被归类为分页I/O。
  • 内存映射文件的同步回写:通过CreateFileMapping + MapViewOfFile将文件映射到进程地址空间后,写入映射内存再调用FlushViewOfFile(或系统自动回写),底层的WriteFile操作会被标记为Paging I/O,因为这种写入本质上是和虚拟内存分页机制交互的。

而"Synchronous Paging I/O"是上述场景的延伸:当WriteFile以同步模式执行(未指定FILE_FLAG_OVERLAPPED)且属于分页I/O场景时,会同时触发该标记。

复现方法

场景1:直接写入系统分页文件

需要管理员权限,且需满足FILE_FLAG_NO_BUFFERING的对齐要求(缓冲区地址、写入大小必须对齐到磁盘扇区大小):

#include <windows.h>
#include <iostream>
#include <malloc.h>

int main() {
    // 获取磁盘扇区大小
    DISK_GEOMETRY diskGeom;
    HANDLE hDisk = CreateFile(L"\\\\.\\C:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
    if (hDisk == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open disk: " << GetLastError() << "\n";
        return 1;
    }
    DWORD bytesReturned;
    DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, &diskGeom, sizeof(diskGeom), &bytesReturned, nullptr);
    CloseHandle(hDisk);
    const DWORD sectorSize = diskGeom.BytesPerSector;

    // 打开系统分页文件
    HANDLE hPageFile = CreateFile(L"\\\\.\\pagefile.sys", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr);
    if (hPageFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open pagefile: " << GetLastError() << "\n";
        return 1;
    }

    // 分配对齐的缓冲区
    char* pBuffer = static_cast<char*>(_aligned_malloc(sectorSize, sectorSize));
    if (!pBuffer) {
        std::cerr << "Failed to allocate aligned buffer\n";
        CloseHandle(hPageFile);
        return 1;
    }
    memset(pBuffer, 0xAA, sectorSize);

    // 同步写入(默认同步模式,无重叠IO)
    DWORD bytesWritten;
    BOOL writeSuccess = WriteFile(hPageFile, pBuffer, sectorSize, &bytesWritten, nullptr);
    if (writeSuccess) {
        std::cout << "Wrote " << bytesWritten << " bytes to pagefile\n";
    } else {
        std::cerr << "WriteFile failed: " << GetLastError() << "\n";
    }

    _aligned_free(pBuffer);
    CloseHandle(hPageFile);
    return 0;
}

场景2:内存映射文件的同步回写

通过内存映射机制触发分页I/O,同时保留FILE_FLAG_NO_BUFFERING实现Non-cached标记:

#include <windows.h>
#include <iostream>
#include <malloc.h>

int main() {
    // 获取磁盘扇区大小
    DISK_GEOMETRY diskGeom;
    HANDLE hDisk = CreateFile(L"\\\\.\\C:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
    if (hDisk == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open disk: " << GetLastError() << "\n";
        return 1;
    }
    DWORD bytesReturned;
    DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, &diskGeom, sizeof(diskGeom), &bytesReturned, nullptr);
    CloseHandle(hDisk);
    const DWORD sectorSize = diskGeom.BytesPerSector;
    const DWORD fileSize = sectorSize * 4; // 4扇区大小,满足对齐要求

    // 创建带NO_BUFFERING的文件
    HANDLE hFile = CreateFile(L"paging_io_test.dat", GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, nullptr);
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "CreateFile failed: " << GetLastError() << "\n";
        return 1;
    }

    // 设置文件大小(必须对齐扇区)
    LARGE_INTEGER fileSizeLi;
    fileSizeLi.QuadPart = fileSize;
    if (!SetFilePointerEx(hFile, fileSizeLi, nullptr, FILE_BEGIN) || !SetEndOfFile(hFile)) {
        std::cerr << "Set file size failed: " << GetLastError() << "\n";
        CloseHandle(hFile);
        return 1;
    }

    // 创建文件映射
    HANDLE hMap = CreateFileMapping(hFile, nullptr, PAGE_READWRITE, 0, 0, nullptr);
    if (!hMap) {
        std::cerr << "CreateFileMapping failed: " << GetLastError() << "\n";
        CloseHandle(hFile);
        return 1;
    }

    // 映射文件视图
    char* pMapView = static_cast<char*>(MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, fileSize));
    if (!pMapView) {
        std::cerr << "MapViewOfFile failed: " << GetLastError() << "\n";
        CloseHandle(hMap);
        CloseHandle(hFile);
        return 1;
    }

    // 写入映射内存
    memset(pMapView, 0xBB, fileSize);

    // 强制回写,触发同步分页I/O
    if (FlushViewOfFile(pMapView, fileSize)) {
        std::cout << "Flushed mapped view to file\n";
    } else {
        std::cerr << "FlushViewOfFile failed: " << GetLastError() << "\n";
    }

    // 清理资源
    UnmapViewOfFile(pMapView);
    CloseHandle(hMap);
    CloseHandle(hFile);
    return 0;
}

验证说明

编译运行上述代码(场景1需管理员权限),在Process Monitor中过滤目标进程的WriteFile操作,即可看到标记为Non-cached、Paging I/O和Synchronous Paging I/O的日志,与第三方应用的行为一致。

内容的提问来源于stack exchange,提问作者tigrou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 20:50:36