Sunday, October 18, 2009

The art of MEM_RESET flag

The MEM_RESET flag has somewhat unfortunate fate of obscurity. The MSDN is concise in its wisdom: "Indicates that data in the memory range specified by lpAddress and dwSize is no longer of interest. The pages should not be read from or written to the paging file. However, the memory block will be used again later, so it should not be decommitted." Đ¢hen adds exemplary: "Using this value [MEM_RESET] does not guarantee that the range operated on with MEM_RESET will contain zeroes. If you want the range to contain zeroes, decommit the memory and then recommit it."

VirtualAlloc with MEM_RESET moves a physical page(s) to the standby list - this means that the physical page might be given to any process who is in want of a wife, I mean memory. Before this unfortunate moment read from that page gets the original content. But if the page has been given to someone else, any access (read or write) to the page results in a soft page fault and a brand new zeroed page is given to the process. Of course the process does not know when the page could be given to someone else so the content can turn into zeroes in any moment.

Now the things becomes interesting.
If the process write to the page and the page is not yet given to someone else - it is a soft-page fault and the page is given back to the process with all its original content! One can think of writing to the page as a way to remove MEM_RESET flag from it (though it seems this flag is not stored at all - it's a one shot action).

The usefulness of the MEM_RESET flag is in cases when we can generate the contents a block of memory faster than hard page fault handler brings these pages into RAM from the swap file. We still prefer to not generate the content if we can access it directly in memory (with the cost of a soft page fault).
Having the above in mind there is an easy scheme to play nicely with the OS and to make hard disk's life less miserable.

Allocate memory, generate whatever content you need.
When your application goes into background (or when you think it's time) - remember the first byte of the page and use VirtualAlloc(MEM_RESET) on that page. When you want the memory back (the application goes to foreground for example), write this remembered byte back and check whether the rest of the page contains zeroes. If that is the case - the page has been stolen from you and you need to generate content again. (Alternatively - we can remember first byte and the offset of any non-zero byte in the page, instead of checking the entire page;)

No comments: