At Loss for Words

…of Programming, Love and Metaphors

Conservative variable size memory sharing

, ,

Using shared memory through Windows API is not difficult when you get over the "file"-oriented nomenclature (CreateFileMapping, MapViewOfFile, “backed by the system paging file”, ...). Sharing block of memory of fixed size is simple. It has already been described thousand times on other places.

Instead, the following article explains how to create a mapping with potential to share hundreds of megabytes, yet still takes only as much memory as is actually necessary, which can be as low as one page of 4 kilobytes.

The following technique exploits one aspect of the behavior of memory mapping objects. Committing a page in the reserved memory-mapped region has effect across all the processes that have the region mapped into their address space. This becomes obvious when one realizes that those really are the same pages, maybe just mapped at different addresses. So let the code (and comments) speak:

if (HANDLE hShare = CreateFileMapping (INVALID_HANDLE_VALUE, NULL,
                                       PAGE_READWRITE | SEC_RESERVE,
                                       0, size,
                                       TEXT ("my cool shared memory"))) {
This is fairly common way to create shared memory, with one very important change: SEC_RESERVE. When we finally map the view... like this:

    if (void * pShare = MapViewOfFile (hShare, FILE_MAP_WRITE, 0,0,0)) {
...we receive pointer to continuous area of "size" bytes (which may be hundreds of megabytes), but none of these pages point to any physical page yet. Attempt to access them at this point will result in crash (segmentation fault). And this actually is the intended initial state of all processes that will use this shared memory.

Access synchronization and passing the length value between processes is not further elaborated. I presume that this is not necessary given the subject.

Once a process needs to share (write) some amount of data, it needs to commit the necessary pages before writing into the shared memory. This is done by following call to VirtualAlloc:

        if (VirtualAlloc (pShare, length, MEM_COMMIT, PAGE_READWRITE)) {
VirtualAlloc formulated exactly like this allocates just enough physical pages to accommodate length bytes and assigns them to our reserved area. It only commits pages that are not already committed, the effect is cumulative, thus calling it again with smaller length will be noop. It will return the value of pShare on success or NULL on out of memory condition.

            std::memcpy (pShare, pImportantData, length);
        };
After memcpy finishes a memory barrier should be inserted (e.g. in form of ReleaseMutex).

The data are then visible and accessible to all other instances. The previous call to commit the pages is immediately in effect across all the processes that use such share, and all of them can now access the memory (up to length bytes, of course).

Conclusion

Even though the mapping object might have reserved megabytes of continuous spaces for worst-case scenario, using this technique ensures that only actually required amount of bytes is allocated.

GetCurrentModuleHandlesprintf-alloca-style string building for constructors

Comments

Unregistered user Wednesday, September 21, 2011 11:02:39 AM

Anonymous writes: Can this handle automatic shrinking?

Jan RingošTringi Wednesday, September 21, 2011 11:14:03 AM

Originally posted by anonymous:

Can this handle automatic shrinking?


VirtualFree API function supports MEM_DECOMMIT flag that releases the memory but keeps the pages reserved. And again you would need to synchronize that operation across processes. Anyway I found out that shrinking is actually rarely really required.

Unregistered user Thursday, September 22, 2011 6:11:20 AM

Anonymous writes: This be very danger by such sharing of memory. Use of such kind trick is what give software bad name and encurridge the hacking people.

Jan RingošTringi Thursday, September 22, 2011 8:49:46 AM

Originally posted by anonymous:

This be very danger by such sharing of memory. Use of such kind trick is what give software bad name and encurridge the hacking people.


I disagree. Sharing memory is fastest way of IPC and very safe if you implement correct synchronization. Also taking advantage of a well documented feature of Windows' VM implementation is not a trick.

Write a comment

New comments have been disabled for this post.