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
相关产品推荐
相关产品推荐

