How do I prefetch data into my memory-mapped file?

A customer created a memory mapping on a large file and found that when the memory manager wanted to page in data from that file, it did so in 32KB chunks. The customer wanted to know if there was a way to increase the chunk size for efficiency.

The memory manager decides the chunk size for memory-mapped files, and the chunk size is currently set to eight pages, which on a system with 4KB pages, comes out to 32KB chunks. (Note that this chunk size is an internal parameter and is subject to change in future versions of Windows. I'm telling a story, not providing formal documentation.)

You have a few options.

The first option is to switch from memory-mapped files to explicit disk I/O. If you do that, then you have full control over the chunk size. It also means that you have finer control over I/O errors, because you will be told of the error in a controlled manner. As opposed to waiting for the exception to occur, and then carefully parsing the exception to verify that it was in your memory-mapped file region (and not in some other part of the address space), and then trying to unwind out of the exception without crossing any frames that are outside your control.

Many people decide not to go this route and stick with the memory-mapped file approach, not because they are really good at writing exception handlers and unwinding safely, but because they really like the convenience of memory-mapped I/O, and if something goes wrong with the I/O, they're fine with the program simply crashing. (Of course, there's the group of people who try to write the really clever exception handler and end up making a bigger mess when they mess up.)

Another option is to go ahead and create your memory-mapped file, but when you are about to do that thing that you want to trigger large-chunk I/O, you can issue sequential Read­File calls from the same file handle into a dummy buffer of, say, 1 megabyte. Do this before you start accessing the memory-mapped version of the file. This will "prefetch" the data off the disk into memory in the large chunks you desire (at a cost of some extra memcpy's).

Comments (16)
  1. No says:

    Another option is to use PrefetchVirtualMemory:…/Hh780543%28v=vs.85%29.aspx

  2. alegr1 says:

    MM files as an IO surrogate are more hassle than they worth.

  3. Joshua says:

    Didn't it occur to you to preread the memory mapped region by dereferencing a pointer at 4k increments?

  4. JM says:

    @alegr1: I wouldn't call them a "surrogate". It's a way of doing I/O, plain and simple. It's when people think it's not that the problems begin. Memory-mapped files are particularly useful for sharing data between processes that's also on disk. Unfortunately, people see memory mapping and think "cool, now I don't have to worry about I/O anymore", which couldn't be more wrong.

    Besides, memory-mapped I/O is way cooler.

  5. Gabe says:

    I like how some PM found this post in Raymond's queue a couple years ago, decided to do something about the problem, and created the API that "No" linked to!

  6. alegr1 says:

    Besides, memory-mapped I/O is way cooler.

    Until you don't have enough address space. Then you have to handle that (map part of the file, remap as necessary), and that becomes a mess.

  7. Danny says:


    It's not years, the "No" link is dated 5th of May, so it's maximum one year :)

  8. @Danny

    Gabe was actually refering to how the blog's posts are put into a queue and the queue can be years in length. It is possible that this post itself was added a year or two ago. So it is possible that some Microsoft Product Manager saw this post in the queue (maybe June 2011, maybe June 2010), brought it to the attention of the Windows higher ups and they thought, yes that is a good idea.

  9. Anonymous says:

    The Unix world has madvise() which provides the kernel prefetch hints.  But it's harder to handle SIGBUS than it is to use SEH to handle IN_PAGE_ERROR.

  10. Ben Voigt says:

    Danny, you have to account for the time for the feature to be designed, specified, implemented, tested, and documented.  Some manager approved this feature quite some time ago.  Raymond's queue might or might not be deep enough to explain it.

  11. Ken Hagan says:

    Since Raymond's post opens with a customer query, is it not more likely that the API was inspired by this real world requirement that had already occurred rather than a suggestion in a blog that wasn't due to see light of day for another year or so?

  12. Neil says:

    Why can't you ReadFile directly into the memory mapping?

    [How could that work? If the mapping is read-only, then you will get an access violation (you specified read-only memory as the output buffer). If the mapping is read-write, then you have a race condition (if the app tries to modify the memory at the same time the I/O manager is writing to it). -Raymond]
  13. name says:

    Can't you ReadFile it into /dev/null?

    [And how would you do that? -Raymond]
  14. Joshua says:

    […If the mapping is read-write, then you have a race condition (if the app tries to modify the memory at the same time the I/O manager is writing to it). -Raymond]

    Personally I would have thought the IO code would have been clever enough to catch this case, but if not than not.

    [How do you expect it to catch this case? And what should it do when it catches it? (Note that modifying the buffer while the read is in progress is explicitly forbidden.) -Raymond]
  15. HandlingMemMapExceptions says:

    Could you please show us some robust exception handler and unwinding code sample to properly manage error conditions with memory-mapped files? Thanks.

  16. Joshua says:

    [How do you expect it to catch this case?]

    My internal model of the Windows kernel suggests this should deadlock (by taking a non-recursive lock twice) if not explicitly checked for so it'd have to check for ReadFile on top of its own memory map.

    If it did catch it, the code is obviously copying blocks within the memory map, so that's how to handle it. The degenerate form of copy to self would indeed prefetch page but make it dirty with no actual changes.

    [I'm not sure what you mean by "copying blocks within the memory map". There is no copying going on. The I/O is pumped directly into the pages. The issue is that while the I/O is in flight, the pages are still writable by the application, so what if it writes to it? Should there by some "Uh-oh, the application wrote to the page too, so I should cancel the I/O" (but what if it's too late to cancel it)? -Raymond]

Comments are closed.