Windows maintains a sophisticated disk caching system to improve performance by storing frequently accessed data in memory. For performance testing scenarios, this caching behavior can distort benchmark results by masking actual disk I/O performance.
While rebooting is the most thorough solution, here are some programmatic alternatives:
// Using PowerShell to clear standby cache
Clear-StorageCache -WhatIf
# Requires Windows 8/Server 2012 or later
For older systems, you'll need to use native API calls:
#include <windows.h>
#include <winioctl.h>
BOOL ClearSystemCache() {
HANDLE hDevice = CreateFile("\\\\.\\PhysicalDrive0",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) return FALSE;
DWORD bytesReturned;
BOOL result = DeviceIoControl(hDevice,
FSCTL_DISABLE_READ_CACHE,
NULL, 0, NULL, 0, &bytesReturned, NULL);
CloseHandle(hDevice);
return result;
}
When you can't clear the cache, force uncached operations:
// C# example using FileOptions
var fs = new FileStream("testfile.dat",
FileMode.Open,
FileAccess.Read,
FileShare.Read,
4096,
FileOptions.RandomAccess | FileOptions.WriteThrough);
Verify cache is actually cleared using Performance Monitor:
- Add "Cache Data Flush Pages/sec" counter
- Monitor before/after your clearing operation
- Administrator privileges are required
- Some methods may affect system stability
- Results may vary across Windows versions
- Consider using RAMMap from Sysinternals for visualization
Windows implements several caching layers including the Standby List (modified page writer) and System Cache. For accurate disk performance measurements during benchmarking, these caches must be purged between test runs.
The most reliable method is using the EmptyWorkingSet
API combined with file system cache flushing:
#include <windows.h>
#include <Psapi.h>
void ClearDiskCache() {
// Flush file system buffers
HANDLE hToken;
TOKEN_PRIVILEGES tp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, 0);
DWORD dummy;
DeviceIoControl(GetModuleHandle(NULL), FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dummy, NULL);
// Clear standby list
SetProcessWorkingSetSize(GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1);
// Alternative: Using SysInternals tool programmatically
// system("RAMMap.exe -EmptyStandbyList");
}
For quick testing without compilation:
# Requires admin privileges
Clear-FileCache
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# Alternative using built-in Windows commands
& rundll32.exe advapi32.dll,ProcessIdleTasks
The behavior differs between Windows versions:
- Windows XP: Requires
EmptyWorkingSet
or third-party tools - Windows 7+: Supports file system cache control via
FSCTL_DISMOUNT_VOLUME
- Windows 10/11: Includes additional memory management APIs
Confirm cache clearance using:
Get-Counter -Counter "\Memory\Cache Bytes" -SampleInterval 1 -MaxSamples 5