NT Cache Setter

This page is available in German language too
  Windows NT, 2000, XP
Under Windows NT, Windows 2000 and XP the file cache can theoretically take nearly all the physical RAM. The upper limits are 512 MB under NT4 and 960 MB under 2000/XP.
Often it seems that the memory of applications is swapped out in favor a large file cache. If you need the application again you see and hear how it is digged up from the pagefile...
Under Windows 9x you where able to limit the size of the file cache thru an entry in the SYSTEM.INI. But there is no similar way under NT, 2000 and XP.

It becomes really worse when a Windows optimizing tool has set 'LargeSystemCache' to 1. This means something like "If Window needs memory, take it from anywhere but not from the file cache".

The only way to get a bit control over the file cache is to trim its 'Working Set'. The Working Set is the memory that has been recently used so Windows expects that it is used again in the near future.
Trimming the Working Set doesn't mean that the memory is taken away from its owner. It only means that the Windows memory management thinks that it's not important to hold it in physical RAM.

Trimming the Working Set of a program is also made by Windows whenever you minimize the program. You can observe it in XP's TaskManager "Mem usage" column. Since Vista it shows it under its correct name.

Trimming the file cache's Workting Set is what Sysinternals CacheSet does. But it does it only on a button click.
That's why I've made NtCacheSetter which does't it periodically. It bases upon the sources provided by SystInternals.

Sample for a commandline of NtCacheSet to trim once a second to a minium of 8 MiB, a maximum of 64 MiB and showing its window:

NtCacheSet /int=1s /min=8M /max=64M /show=1
/int sets the interval in milliseconds or with unit s (Seconds)

/min sets the minimum value in Bytes or with unit KiB, MiB, GiB (K, M, G are good enough)

/max sets the maximum value in Bytes or with unit KiB, MiB, GiB (K, M, G are good enough)

The default values are 1 Second for the interval, 1/16 of the physical RAM for the maximum and 1/4 of the maximum for the minimum.

Start NtCacheSet again to remove a previous invisible instance from memory.

The periodic cache set call is performed only if the current cache working set size is at least 10 percent above the maximum value. In the window this is indicated by the 'LED':
Gray : Idle
Green: Values checked but cache not adjusted
Red : Values checked and cache adjusted
For testing with different values you can click them and enter new ones in an inputbox. Yes, that's a bad GUI design.

I'm not sure if this tool is useful, but I think so, especially since Microsoft introduced a function for permanently limiting the file cache with Windows 2003 Server SP1.
But periodically trimming the cache's working set is no good solution. Let's call it an experiment...

Here is an interesting article from the "Windows 2000 Performance Guide":
File Cache Performance and Tuning


  Windows 2003 Server SP1, Vista, Win7/8/10, Server 201x
With the SP1 for Windows 2003 Server Microsoft implemented a new API function for limiting the file cache's working set minimum and maximum size permanently: SetSystemFileCacheSize.

I've made a little tool with the same name to use it. It needs command line parameters to do something.

Commandline samples:

shows the current Windows settings

SetSystemFileCacheSize /?
shows this help

SetSystemFileCacheSize 8 128
sets the min size to 8 MB and the max size to 128 MB

SetSystemFileCacheSize off 128
disables min size and sets the max size to 128 MB

SetSystemFileCacheSize off off
disables min and max size

SetSystemFileCacheSize flush
flushes the file cache

Must be started with admin privileges.

Shows a messagebox if required, otherwise it's invisible and returns an errorlevel 0.

For values > 4096 MB on x64 systems use the included x64 version.

In contrast to SysInternals CacheSet SetSystemFileCacheSize sets a real permanent limit for the file cache's working set size and I think this is useful to prevent application's memory is swapped out to the pagefile in favor of a large file cache.
Limiting its working set does not mean that the cache manager will never use more memory for cache than the limit defines. It's the working set only which is limited. You will still have a large cache when there is enough availlable memory. But running processes are no more the favourite victim when new cache memory is required.

Under Windows 10 build 15063 (aka release 1703, aka Creators Update) the SetSystemFileCacheSize API call has no more effect. NtCacheSet still works.
With release 1709 it works again.


Meanwhile Microsoft addresses the problem too:


  Behaviour of the Windows file cache and how to test it
I've written another little tool for some simple tests of the Windows file cache:

It writes to or reads from a file using different flags for for the Win32 API function CreateFile. Here is what the options apparently mean. All observations are made under XP SP2 and LargeFileCache=0

no flag:
Windows assumes nothing and works well.

Windows assumes random access and blows up the cache's working set aggressively and if required it swaps out your running applications unashamed to the pagefile. Later you can feel and hear how the app's memory is digged out of the pagefile, apparently without any read optimization. Vista's "ReadyBoost" will try to heal the symptoms...
For software developers: Use it very very carefully if you deal with large files!

Windows assumes a sequential access. More read ahead buffer und read ahead is done even the previous accesses where not sequential. Not too much effect.

Windows does not use any file cache or buffering - by far the best way to read or write a file once. No buffering at all, the data is transferred directly from or to the buffer provided by the application (unless the file is NTFS compressed).
For software developers: The buffer has to be sector aligned, that's all. Todays hard drives have a maximum sector size of 4096 Bytes, CDs 2048 Bytes. You can check it by means of DeviceIoControl call with IOCTL_DISK_GET_DRIVE_GEOMETRY.
The easiest way is to get an aligned buffer is to use VirtualAlloc which provides 64K aligned memory, which should be good enough even for future hard drives with larger sectors. In C/C++ _aligned_malloc is ok too. And you have to read or write complete sectors which might be difficult but it's worth!

Writes goes thru the cache without buffering to the disk but data is stored in the cache too so following read accesses to the just written data come out of the cache.
Furthermore it shall request a write-through or immediate flush of the hard drives internal cache.

With 'flush at finish' the cache is flushed at the end of the write. If there is no write cache then the flush time is null or nearly null. This is the case on FAT formatted USB 'removable' drives, even with the removal policy 'Optimize for speed'. Since invented with XP this policy pretends to activate a write cache but this is true only on FAT formatted USB hard drives. On USB 'removable' drives the policies have no effect.
Only when the block size goes below 4096 Bytes write accesses on USB 'removable' drives are buffered. This way you can blow 20 MB of data into the write cache of a USB drive which is 'Optimized for fast removal'...
On NTFS formatted USB 'removable' drives the magic limit seems to be at 512 KB.

With "create and delete files" empty files are created and then deleted. This shows if write accesses to the file system are buffered or not.



NtCacheSetter, SetSystemFileCacheSize and FileCacheTest are Freeware.

Download NtCacheSetter V0.4:

Download SetSystemFileCacheSize V0.3:

Download FileCacheTest:

It's made with VB6 because:

  • creating a GUI using pure Win32 or MFC is just wasted time
  • using Borland C++ Builder gives an EXE of at least a half MB
  • using .NET gives an 40K EXE but the user have to download a monster size framework - no, thanks
  • VB6 runtimes dlls come with W2K, XP, Vista, Win7/8/10 and the Servers; VB6 is just great for small tools with a GUI
Just in case the VB6 runtimes are missing put the msvbvm60.dll in the same folder a the exe or into the Windows or Windows\System32 folder:


last change: 17 April 2017

Uwe Sieber