Win32应用磁盘缓存使用调查及FILE_FLAG_NO_BUFFERING性能分析
关于Windows文件缓存与FILE_FLAG_NO_BUFFERING的性能分析
我的工作负载场景
核心逻辑大致如下:
while True: data = get_data_from_network(); filename = sha1(data); write_to_file(filename, data, data.size());
我偶尔会回读文件,但频率很低。当前核心压力是处理大量网络请求,经常需向磁盘写入高达1GB的数据,绝大多数时间都在执行流式磁盘写入操作。
曾有技术建议指出:
如果应用会回读文件,读取操作可以直接从磁盘缓存完成,完全避免物理I/O。
但我不确定该建议是否适配我的场景——由于缓存容量有限,等我需要回读时,之前的数据很可能已被新写入的数据挤出缓存。
我考虑在调用CreateFile()时使用FILE_FLAG_NO_BUFFERING绕过系统缓存,但不想盲目操作,希望从性能角度深入分析影响。除了给应用计时,我还想明确以下问题:
核心问题解答
1. 操作系统缓存的基本属性
- 作用范围:Windows文件缓存是全局的,由所有进程共享,并非按进程或文件单独分配。
- 容量规则:缓存大小无固定值,系统会根据物理内存使用情况动态调整——内存充足时会尽可能扩容,其他进程需要内存时会自动收缩释放空间。
- 可配置性:可通过组策略或注册表调整缓存的最小/最大值(如修改
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management下的相关项),但通常建议由系统自动管理,手动配置易引发内存分配失衡。 - 编程查询:可通过
GetSystemInfo()和GetPerformanceInfo()API获取系统内存及缓存统计数据,比如从PERFORMANCE_INFORMATION结构体中提取缓存使用情况。
2. 如何判断工作负载是否导致缓存颠簸
缓存颠簸的核心表现是系统频繁将缓存数据换出到磁盘,同时不断载入新数据,导致磁盘I/O激增、内存使用率大幅波动。可通过以下方式排查:
- 用性能监视器(Performance Monitor)跟踪
Memory\Cache Bytes计数器,观察是否在短时间内频繁大幅波动; - 跟踪
PhysicalDisk\% Disk Time和PhysicalDisk\Avg. Disk Queue Length,若这两个指标持续偏高且缓存大小频繁变化,大概率存在缓存颠簸; - 使用
xperf等性能分析工具捕获文件I/O跟踪数据,查看缓存命中/未命中的频率。
3. 如何统计缓存命中的磁盘读取量
要确定多少磁盘读取来自内存缓存而非物理介质,可通过以下方法:
- 性能监视器中,
LogicalDisk\Disk Read Bytes/sec是总读取量,Memory\Cache Read Bytes/sec是缓存读取量,两者差值即为物理磁盘读取量; - 用
xperf捕获I/O事件,分析FileRead类别的事件,区分缓存命中(IrpFlags不含IRP_NOCACHE标记)和物理磁盘读取的情况; - 编程层面可结合
CreateFile()的相关标志与GetFileInformationByHandleEx()获取部分缓存信息,但最准确的方式还是依赖系统性能监控工具。
4. FILE_FLAG_NO_BUFFERING的性能影响分析
针对你的流式写入场景,使用该标志的利弊如下:
- 优势:
- 避免大量写入数据占用全局缓存,减少对其他进程的内存资源抢占;
- 跳过缓存写入的额外内存拷贝,理论上可降低CPU开销;
- 不会因缓存颠簸触发额外的后台磁盘刷盘操作。
- 劣势:
- 必须严格遵循对齐要求:写入缓冲区地址、写入大小必须与磁盘扇区大小对齐(通常为4KB或更大),否则调用会失败;
- 偶尔的回读操作必须直接访问物理磁盘,无法享受缓存加速,会增加延迟;
- 若写入模式并非严格顺序流式,可能引发更频繁的随机I/O,反而降低性能。
建议先通过性能监控工具评估当前缓存使用情况:如果你的写入操作已导致缓存占满、频繁刷盘,且回读频率极低,启用FILE_FLAG_NO_BUFFERING会带来明显性能收益;若缓存仍有充足空间,且偶尔回读的性能影响可接受,保留系统缓存会更稳妥。
内容的提问来源于stack exchange,提问作者Zachary Turner
相关产品推荐
相关产品推荐

