The Depths of Windows Memory (Part 3) — Section Objects and Copy-on-Write: What DLLs and File Mappings Really Are

· Updated: · · Windows, Memory Management, Shared Memory, File Mapping, Copy-on-Write, DLL, Cache Manager

Revision history (first version, published Aug 20, 2026)
First published
Cite this article(DOI (registered archive): 10.5281/zenodo.22170867)

The DOIs below refer to previously archived versions and may not match the current text. Use this page’s URL to reference the current text.

Go Komura (2026). The Depths of Windows Memory (Part 3) — Section Objects and Copy-on-Write: What DLLs and File Mappings Really Are. KomuraSoft LLC. https://comcomponent.com/en/blog/windows-memory-internals-section-copy-on-write/

DOI (registered archive)
10.5281/zenodo.22170867
DOI (last registered version)
10.5281/zenodo.22170868

“If 100 processes use the same kernel32.dll, do we need 100 sets of code pages?” Part 3 starts from the question that arises when multiple processes use the same contents. When two processes memory-map the same file, can a page that one of them read be used by the other?

The answer lies in a mechanism that maps different virtual addresses onto the same physical page. At the center of the unit of sharing is the section object. And the mechanism that privatizes only the pages that need it, at write time, is copy-on-write (CoW).

In the previous article, “The Depths of Windows Memory (Part 2) — The Life of a Physical Page”, we followed how a page that leaves the Working Set moves through Modified, Standby, Free, and Zeroed. Standby also keeps pages from DLLs, EXEs, mapped files, and the file cache. This time we add the perspective of sharing across multiple processes.

We look at EXEs and DLLs, data files, pagefile-backed shared memory, and the file cache in turn, and then distinguish the cache, data, and image paths on the same file stream. For how to read the numbers, the introductory article “What Does Windows’ “Memory Usage” Actually Mean?” is assumed.

“The Depths of Windows Memory” — All 3 Parts

This series proceeds in the order obtain a physical page → follow residency and reclamation → understand sharing and privatization.

Part Theme What this part follows
Part 1 Virtual addresses and page faults When a region allocated with VirtualAlloc obtains physical RAM
Part 2 The life of a physical page The state transitions of a page that leaves the Working Set, and the role of the page file
Part 3 (this article) Section objects and copy-on-write How DLLs, file mappings, and shared memory share physical pages

Part 3 answers just one question.

Why can multiple processes use the same DLL or file as a single set of physical pages?

Before you start Details
Intended readers Developers and operators who want to understand, from the internal structures, how DLL sharing, CreateFileMapping, MapViewOfFile, shared memory, CoW, and the file cache relate to one another
Environment Windows 10/11 or a current Windows Server
Prerequisites Basics of virtual addresses, page faults, and the Working Set
Difficulty Intermediate. Internal terms such as Control Area and Prototype PTE also appear

For observation we use VMMap, Process Explorer, and QueryWorkingSetEx.

In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (19 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle

1. The Bottom Line First

The overall picture comes down to the following three points.

  1. Separate the shared contents from the address each process sees. A section object represents a shareable memory range, and each process maps part of it as a view. Even when they use the same section offset, the views’ virtual addresses need not match.12
  2. Separate what backs the contents from the path through which they are used. Some sections are backed by a real file and some by the page file. An EXE/DLL is an image section; an ordinary file mapping is a data section. With SEC_IMAGE, the page protection is decided by the attributes inside the PE. The cache, data, and image paths must not be lumped together either.234
  3. Confirm CoW privatization through the per-page sharing state. Pages are shared while they are being read; only a page that is written gets copied, and that process’s PTE is swapped. Because FILE_MAP_COPY charges Commit for the entire view up front, Private Bytes alone cannot establish that CoW happened. Use the Shared bit from QueryWorkingSetEx to confirm it.567

In one sentence: what is shared is not the virtual address, but the contents inside the section and the physical pages that correspond to them at that moment.

What you want to know Sections to read
How sections, views, and backing stores relate Sections 2 to 3
DLL sharing and CoW at write time Sections 4 to 6
The difference from the Cache Manager, and why things stay in use after closing Sections 7 to 8
Confirming sharing and privatization with two processes Sections 9 to 10

2. Section Objects and Views

In Microsoft’s definition, a section object represents a region of memory that can be shared, and it is also the mechanism that maps a file into a process’s address space.1

The key to understanding it is to think of the section itself and the view each process sees as separate things.

Concept Role
Section object Represents the shared contents, the size, the backing store, and the upper bound on protection
View Exposes part of the section as a virtual address range in one process
PTE Binds each virtual page in the view to the current physical page, or to a not-yet-materialized state
PFN Represents a physical page that actually exists in RAM

The Win32 API is read along the same division of roles.3

Step What you get
CreateFileMapping A handle to a file mapping object
MapViewOfFile A view placed in the process’s virtual address space
First access to the view The accessed page being bound to physical memory through a page fault

Let us start with an example that maps a read-only file.

HANDLE mapping = CreateFileMappingW(
    file,
    nullptr,
    PAGE_READONLY,
    0,
    0,
    nullptr);

void* view = MapViewOfFile(
    mapping,
    FILE_MAP_READ,
    0,
    0,
    0);

Calling CreateFileMapping alone does not yet give the process an address it can read. And creating a view does not immediately bring every page into RAM either. Starting with the first page that is touched, page faults read in the file contents and bind physical pages to the PTEs.8 In other words, the demand paging we saw in Part 1 applies to section views exactly as it is.

2.1. Same Section, Different Virtual Addresses

Even when process A and process B map the same offset of the same section, the start addresses of their views can differ.

Mapping different virtual addresses onto the same physical pageProcess A and process B each have a view at a different virtual address, but both reach the same physical page PFN X through the same section offsetProcess A: 0x000001A00000 + 0x3000Section offset 0x3000Process B: 0x000002700000 + 0x3000Same physical page PFN X

Figure 1: What is shared is the contents inside the section and the physical page, not the virtual address.

This is why you must not store raw pointers in shared memory. A pointer value from process A may be an unrelated address in process B.

In a shared structure, use offsets from the start of the view, fixed-width integers, an explicit version, and explicit alignment. Microsoft’s MapViewOfFileEx documentation also recommends storing offsets from the base rather than pointers, because there is no guarantee that the same address will be available in the future.6

3. File-Backed and Pagefile-Backed

Sections divide into two broad kinds according to where their contents can be restored from.

How file-backed and pagefile-backed sections divergePassing a real file to CreateFileMapping produces a file-backed section whose clean pages can be re-read from the original file. Passing INVALID_HANDLE_VALUE produces a pagefile-backed section whose contents are backed by the page file and disappear when the object is destroyedPass a handle to a real filePass INVALID_HANDLE_VALUECreateFileMappingFile-backed sectionPagefile-backed sectionClean pages can be re-read from the original fileContents are backed by the page file and disappear when destroyed

Figure 2: The difference in backing store decides where the contents can be restored from and how long they live.

3.1. File-Backed Sections

Passing a real file to CreateFileMapping produces a file-backed section.

  • A read-only view reads the pages it needs from the file.
  • Changes made through a read/write view are treated as data of that file.
  • Changes made through a CoW view are not written to the original file; they become private pages.

If a file-backed page is clean, the physical page can be discarded and re-read from the original file later. This property is what supports the efficiency of Standby and the file cache we saw in Part 2.

3.2. Pagefile-Backed Sections

Passing INVALID_HANDLE_VALUE as the hFile of CreateFileMapping and specifying a size produces a pagefile-backed section.

HANDLE mapping = CreateFileMappingW(
    INVALID_HANDLE_VALUE,
    nullptr,
    PAGE_READWRITE,
    0,
    64 * 1024,
    L"Local\\KomuraMemoryDemo");

This section has no explicit data file; its contents are backed by the page file. The initial contents are zero. To use the same object from multiple processes, use a name, handle inheritance, DuplicateHandle, or similar.93

Changes to a shared page are visible, but this is not persistent storage. Processes that map the same shared page can see the changes. On the other hand, once the section object is destroyed the contents do not survive, so it is not suited to standing in for a persistent file.2

One caution: shared memory does not come with mutual exclusion built in. A mutex, semaphore, event, lock-free protocol, or the like has to be designed separately.9

4. Image Mapping and Data Mapping

When we say “an EXE or DLL is also a file mapping”, the differences from an ordinary data file still need to be kept in view.

Item Image mapping Data mapping
Main use Loading EXEs and DLLs Ordinary files, shared data
Creation attribute SEC_IMAGE PAGE_READONLY, PAGE_READWRITE, and so on
Page protection Decided by the attributes inside the PE image Decided by what the mapping and the view specify
Writes Can be privatized through a writable section or CoW Either shared write or CoW can be chosen
VirtualQuery Type MEM_IMAGE MEM_MAPPED

With SEC_IMAGE, the section attributes of the executable image itself, rather than the ordinary protection value passed to CreateFileMapping, decide the page protection of the view.3

4.1. Not Every Page of a DLL Is Necessarily Shared

Pages that never change, such as code, can share the same physical page across many processes. Pages that need process-specific changes diverge through CoW.

That said, ASLR relocation, loader fixups, hotpatching, the actual PE section attributes, and other factors all have an effect. Even when the same DLL is loaded, not every page is necessarily shared.

What matters is the design: share the shareable pages first, and lazily copy only the pages that need changes.

5. Copy-on-Write from Start to Finish

Let us follow the sequence from the state in which two processes are reading the same CoW page to the point where only Process A writes one byte.

5.1. Before the Write

Before any write happens, the PTEs of both processes conceptually reach the same shared page, and reads simply succeed.

Shared state before copy-on-writeBefore any write happens, process A's PTE and process B's PTE both reach the same shared page PFN X, and reads simply succeedProcess A PTEShared PFN X (read / copy-on-write)Process B PTE

Figure 3: Before the write, both processes’ PTEs point at the same physical page.

5.2. A Protection Fault on the Write

A CoW page is not an ordinary shared writable page to begin with. When Process A tries to write, the CPU raises a protection fault. The memory manager, on receiving control, determines that this is not an illegal write but a write to a page with the CoW attribute.

5.3. Creating a New Physical Page

Having made that determination, Windows does the following.

  1. Obtain one physical page for Process A.
  2. Copy the contents of PFN X to the new page, PFN Y.
  3. Swap Process A’s PTE over to PFN Y.
  4. Change the protection on Process A’s side to ordinary read/write.
  5. Re-execute the write instruction that failed.
Diverged state after copy-on-writeIn response to process A's write, only process A's PTE is swapped to the private page PFN Y that received a copy of the contents, while process B's PTE keeps pointing at the original shared page PFN XContents copied at write timeProcess A PTEPrivate PFN Y (read/write, after the change)Process B PTEShared PFN X (original contents)

Figure 4: Only the writing process’s PTE is swapped to a new private page; the other process keeps reading the original contents.

Process B keeps reading the original contents and never sees Process A’s change. This is copy-on-write. DLL sharing and FILE_MAP_COPY both use the same principle: do not copy until a write happens.56

5.4. The Difference from FILE_MAP_WRITE

The criterion for choosing is whether you want the other side to see your writes, or want the changes to be yours alone.6

View What happens after a write
FILE_MAP_WRITE As a shared write, the change is also visible from other views that use the same file mapping
FILE_MAP_COPY Only the pages that are written become process-private. The changes are not written back to the original file and are lost when the view is unmapped

Do you want to “propagate updates through shared memory”, or do you want “each process to make its own private changes starting from common initial data”? Depending on the goal, the choice is the exact opposite.

6. Still MEM_MAPPED / MEM_IMAGE After CoW

Here we separate where a region came from from the current sharing state of its physical pages.

A page after CoW is physically private, but the Type from VirtualQuery does not change to MEM_PRIVATE. A data view stays MEM_MAPPED, and an executable image stays MEM_IMAGE. That is because Type indicates which initial allocation the region originated from.7

To see per page whether CoW has already happened, use the following procedure.

  1. Access the target page so that it becomes resident.
  2. Get the page’s Working Set information with QueryWorkingSetEx.
  3. Look at the Shared bit.
  4. If Shared == 0, that resident page is private.

When checking in VMMap as well, look not only at the region’s Type but at the Private/Shareable breakdown of the Working Set.

6.1. Private Bytes May Not Increase

FILE_MAP_COPY privatizes only the pages that are written. When Commit is charged, however, is a separate matter.

To prepare for the possibility that every page in the view will be written in the future, Windows charges Commit equivalent to the entire view at map time.6 So Private Bytes does not necessarily grow by 4 KiB the instant the first page is written.

The metrics to prioritize when observing CoW are the following.

  • The Shared bit from QueryWorkingSetEx
  • Private WS / Shareable WS in VMMap
  • Physical page information in RAMMap
  • Private Bytes, as supplementary information only

If your only pass/fail criterion is “did Private Bytes increase at the moment of the write”, you will overlook CoW that is working correctly.

7. Where the Cache Manager Comes In — Separating Three Paths

Saying “EXE/DLL loading, the file cache, and shared memory are all sections” gives you the overall picture, but you must not collapse the implementation into a single object.

A file stream has a SECTION_OBJECT_POINTERS structure used by the memory manager and the Cache Manager.

typedef struct _SECTION_OBJECT_POINTERS {
    PVOID DataSectionObject;
    PVOID SharedCacheMap;
    PVOID ImageSectionObject;
} SECTION_OBJECT_POINTERS;

This structure ties a file object to the sections of a file stream and tracks the in-memory contents and cache information.4 The state each field points to, and the processing path, are separate, however.

Path Corresponding field Role in processing
Cached ReadFile / WriteFile SharedCacheMap The Cache Manager uses cache views
Mapping fault on a data file DataSectionObject The memory manager handles it on the data section side and coordinates with cached I/O on the same file stream to keep the contents consistent
Image fault on an EXE/DLL ImageSectionObject The memory manager handles it with the image section and paging I/O. This path does not go through SharedCacheMap

The connection to the I/O series is that these three are tied together on the same file stream. Do not read this as “every path goes through the Cache Manager”.

Three paths tied to the same file streamCached ReadFile/WriteFile uses SharedCacheMap, a data-mapping fault uses DataSectionObject, and an EXE/DLL image fault uses ImageSectionObject, and the three are tied to the same file stream through SECTION_OBJECT_POINTERSCached ReadFile / WriteFileSharedCacheMapData-mapping faultDataSectionObjectEXE/DLL image faultImageSectionObjectSame file stream (SECTION_OBJECT_POINTERS)

Figure 5: The three paths are processed separately, but they are tied together on the same file stream.

What the three have in common is not that “everything enters the Cache Manager”; it is that the same file stream ties together separate states, the cache, the data section, and the image section, through SECTION_OBJECT_POINTERS.4 Cache reads and writes, the Lazy Writer, and the relationship between Cc and Mm are covered in “The Depths of Windows I/O (Part 4) — Cache Manager and WriteFile”.

Note that when a memory-mapped view is mixed with ReadFile/WriteFile, there is no guarantee that both always see the contents of the same instant. The design has to include synchronization, flushing, and the file sharing mode.36

8. Lifetime of the Object and the View

Closing a handle and unmapping a view are separate things. Closing the handle from CreateFileMapping alone does not remove existing views.

A view holds an internal reference to the section. Only after every view has been unmapped with UnmapViewOfFile and every handle closed with CloseHandle does the object become eligible for destruction.3

UnmapViewOfFile(view);
CloseHandle(mapping);
CloseHandle(file);

This separation of lifetimes is the cause of the phenomenon “I closed the file, but it is still in use”. Even after the file handle is closed, if an image section or a data view still references the file stream, the final close of the file comes later.

For the relationship to cleanup/close on the I/O side, see “The Depths of Windows I/O (Part 1)”; for implementation pitfalls, see “Shared Memory Pitfalls and Practical Best Practices”.

9. See It for Yourself

9.1. Looking at the Same DLL in Two Processes

First, confirm DLL sharing with existing processes.

  1. Start Process Explorer as administrator.
  2. Start two instances of cmd.exe.
  3. Choose View > Lower Pane View > DLLs.
  4. Confirm the path and mapping of the same DLL in both processes.
  5. Open each cmd.exe in VMMap and compare the Working Set, Private, and Shareable figures for Images.

Seeing the same DLL alone does not prove that the PFNs match

Seeing the same DLL in Process Explorer is evidence that both processes have mapped the same image. By itself, however, it does not prove that the PFN of each page matches. Combine the Shareable breakdown in VMMap, RAMMap, and QueryWorkingSetEx to confirm sharing at page granularity. Process Explorer and VMMap are provided by Sysinternals.1011

9.2. Observing FILE_MAP_COPY in Two Processes

The following program maps the same file as a CoW view and prints the Shared bit from QueryWorkingSetEx. The file mapping object is created with PAGE_READONLY, but that protection is compatible with a FILE_MAP_COPY view, and the first write on the view side triggers CoW.3

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <psapi.h>

#include <cstdio>
#include <cwchar>

#pragma comment(lib, "Psapi.lib")

void PrintPage(const char* stage, void* address)
{
    MEMORY_BASIC_INFORMATION mbi{};
    if (!VirtualQuery(address, &mbi, sizeof(mbi))) {
        std::printf("VirtualQuery failed: %lu\n", GetLastError());
        return;
    }

    for (int attempt = 0; attempt < 3; ++attempt) {
        // The page may have been trimmed while the user was waiting.
        // Touch it immediately before querying the working-set attributes.
        volatile unsigned char resident =
            *static_cast<volatile unsigned char*>(address);
        (void)resident;

        PSAPI_WORKING_SET_EX_INFORMATION ws{};
        ws.VirtualAddress = address;
        if (!QueryWorkingSetEx(GetCurrentProcess(), &ws, sizeof(ws))) {
            std::printf("QueryWorkingSetEx failed: %lu\n", GetLastError());
            return;
        }

        if (!ws.VirtualAttributes.Valid) {
            Sleep(0);
            continue;
        }

        std::printf(
            "%s: Type=0x%lx Valid=1 Shared=%llu ShareCount=%llu\n",
            stage,
            static_cast<unsigned long>(mbi.Type),
            static_cast<unsigned long long>(ws.VirtualAttributes.Shared),
            static_cast<unsigned long long>(ws.VirtualAttributes.ShareCount));
        return;
    }

    std::printf(
        "%s: page is not resident; Shared/ShareCount were not interpreted\n",
        stage);
}

int wmain(int argc, wchar_t** argv)
{
    if (argc != 3) {
        std::fwprintf(stderr, L"usage: cow_demo <file> <read|write>\n");
        return 2;
    }

    HANDLE file = CreateFileW(
        argv[1], GENERIC_READ, FILE_SHARE_READ,
        nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (file == INVALID_HANDLE_VALUE) return 3;

    HANDLE mapping = CreateFileMappingW(
        file, nullptr, PAGE_READONLY, 0, 0, nullptr);
    if (!mapping) {
        CloseHandle(file);
        return 4;
    }

    auto* view = static_cast<unsigned char*>(
        MapViewOfFile(mapping, FILE_MAP_COPY, 0, 0, 0));
    if (!view) {
        CloseHandle(mapping);
        CloseHandle(file);
        return 5;
    }

    volatile unsigned char value = view[0];
    (void)value;

    std::puts("Start the other process. When both are waiting, press Enter...");
    (void)std::getchar();
    PrintPage("before", view);

    if (std::wcscmp(argv[2], L"write") == 0) {
        std::puts("Press Enter to trigger copy-on-write...");
        (void)std::getchar();
        view[0] ^= 0x5a;
        PrintPage("after write", view);
    } else {
        std::puts("After the writer changes its page, press Enter...");
        (void)std::getchar();
        PrintPage("reader after peer write", view);
    }

    std::puts("Press Enter to exit...");
    (void)std::getchar();

    UnmapViewOfFile(view);
    CloseHandle(mapping);
    CloseHandle(file);
}

Build it and open the same file in two processes

Build and prepare.

cl /std:c++20 /EHsc /W4 cow_demo.cpp

$path = "$env:TEMP\\cow-demo.bin"
[IO.File]::WriteAllBytes($path, [byte[]]::new(65536))

Then open the same file from two consoles.

.\\cow_demo.exe "$env:TEMP\\cow-demo.bin" read
.\\cow_demo.exe "$env:TEMP\\cow-demo.bin" write

Keep the order of pressing Enter and the values to look at separate

Order Action What to confirm
1 Start both, then press Enter first on the read side and then on the write side Shared is set in before on both
2 Press Enter once more on the write side The writing process’s page now has Shared 0
3 Then press Enter on the read side The reader keeps reading the original page

The Type from VirtualQuery stays MEM_MAPPED even after the write. Check the change in sharing state and the value of Type separately.

Interpret only results where Valid is set

Note that PrintPage re-touches the target page immediately before querying, and if Valid == 0 it retries up to three times without interpreting Shared and ShareCount. If the page still is not resident, it produces no result and says so. Because ShareCount can vary with timing and memory pressure, look at the change in the Shared bit confirmed with Valid == 1, not at a fixed value.

10. Five Misreadings to Avoid in Practice

10.1. “Shared memory ends up at the same virtual address”

What is shared is the section and the physical pages. Because a view’s virtual address can differ per process, store offsets, not raw pointers.

10.2. “If it is the same DLL, every page is necessarily shared”

Clean code pages are easy to share, but relocation, writable sections, CoW, and the residency state at the moment of measurement also produce private pages.

10.3. “After CoW it becomes MEM_PRIVATE”

The Type from VirtualQuery stays MEM_MAPPED or MEM_IMAGE. Confirm the actual sharing state with QueryWorkingSetEx.7

10.4. “If Private Bytes did not increase, CoW did not happen”

FILE_MAP_COPY charges Commit for the entire view up front. Prioritize Private WS and the Shared bit.6

10.5. “If the page is shared, no synchronization is needed”

Seeing the same physical page and being able to update it safely from multiple CPU cores are different problems. Design for atomicity, memory ordering, mutual exclusion, intermediate state at crash time, and version compatibility.

The idea of tracking references and lifetimes separately also applies to the problem of a process lingering after Excel COM interop. See also “Why EXCEL.EXE Processes Remain After Excel COM Interop”.

11. Summary

  • A section object represents a shareable memory range, and each process maps it into its own virtual address space as a view.1
  • The same offset of the same section is mapped from different virtual addresses onto the same physical page.2
  • A file-backed section is backed by a real file; a pagefile-backed section backs named shared memory and the like.9
  • EXEs/DLLs are handled as image sections and ordinary files as data sections; their protection and write-back destinations differ.3
  • CoW shares physical pages while they are being read, and on the first write copies only that page and swaps the PTE.5
  • Because VirtualQuery still returns MEM_MAPPED/MEM_IMAGE after CoW, confirm with the Shared bit from QueryWorkingSetEx.7
  • With FILE_MAP_COPY, Commit for the entire view is charged up front, so CoW cannot be judged from Private Bytes alone.6
  • The Cache Manager’s cached I/O, data mapping, and image mapping are separate paths that use SharedCacheMap, DataSectionObject, and ImageSectionObject respectively, tied together on the same file stream.4
  • Shared memory becomes safe only when the lifetimes of views and handles, synchronization, ACLs, and offset design are all accounted for.

That completes all three parts of “The Depths of Windows Memory”. Reserve and Commit a virtual address, obtain a physical page through a page fault, move it from the Working Set onto the page lists, share it through a section, and diverge only the written pages through CoW — Windows memory management is connected as this one continuous flow.

KomuraSoft LLC handles investigations of defects in Windows applications involving shared memory, file mapping, DLL loading, file locking, inter-process communication, and memory usage.

References

  1. Microsoft Learn, Section Objects and Views. On a section object representing a shareable memory range, and each process mapping part of the section as a view. ↩ ↩2 ↩3

  2. Microsoft Learn, File-Backed and Page-File-Backed Sections. On file-backed and pagefile-backed sections, CoW, and the ability to share the same physical memory from the virtual addresses of different processes. ↩ ↩2 ↩3 ↩4

  3. Microsoft Learn, CreateFileMappingW function. On file mapping objects, pagefile-backed sections, SEC_IMAGE, the lifetime of views and handles, and the consistency of views that back the same file. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  4. Microsoft Learn, SECTION_OBJECT_POINTERS structure. On DataSectionObject, SharedCacheMap, and ImageSectionObject tying a file stream’s mapping and cache information to the memory manager and the Cache Manager. ↩ ↩2 ↩3 ↩4

  5. Microsoft Learn, Memory Protection. On multiple processes sharing the physical pages of the same DLL, and CoW copying to a new physical page and updating the PTE when one of them writes. ↩ ↩2 ↩3

  6. Microsoft Learn, MapViewOfFileEx function. On CoW with FILE_MAP_COPY, private pages being backed by the page file, Commit being charged for the entire view, and storing offsets rather than virtual addresses. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  7. Microsoft Learn, VirtualQuery function. On Type staying MEM_MAPPED/MEM_IMAGE after CoW, and privatization being confirmable through the Shared bit from QueryWorkingSetEx. ↩ ↩2 ↩3 ↩4

  8. Microsoft Learn, Managing Memory Sections. On physical memory not being allocated until the view is accessed, and the page fault on first access reading in the file contents. ↩

  9. Microsoft Learn, Sharing Files and Memory. On sharing the same file mapping object by name or handle, creating pagefile-backed shared memory with INVALID_HANDLE_VALUE, and synchronization being required separately. ↩ ↩2 ↩3

  10. Microsoft Learn, Process Explorer - Sysinternals. On Process Explorer being able to display a process’s handles and its loaded DLLs and memory-mapped files. ↩

  11. Microsoft Learn, VMMap - Sysinternals. On VMMap breaking a process’s virtual memory down into Image, Mapped File, Private, and so on, and displaying the Private/Shareable breakdown of the Working Set. ↩

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

These topic pages place the article in a broader service and decision context.

This article connects naturally to the following service pages.

Frequently Asked Questions

Common questions about the topic of this article.

Does each process that uses the same DLL get a full copy of that DLL in RAM?
Usually not. Unmodified pages of the same image are mapped from each process's different virtual addresses onto the same physical page. Only the pages that need a write become process-specific physical pages, through copy-on-write and similar mechanisms.
Does CreateFileMapping allocate memory to the process at that moment?
CreateFileMapping creates a file mapping object, but it is MapViewOfFile that makes it visible in the process's virtual address space. Beyond that, the view's physical pages are normally materialized by page faults, starting with the first page that is accessed.
What is the difference between FILE_MAP_WRITE and FILE_MAP_COPY?
A change through FILE_MAP_WRITE is a write that is applied to the shared file data. FILE_MAP_COPY shares the initial pages, but only the pages that are written become process-private copies; the changes are not written back to the original file and are lost when the view is unmapped.
After copy-on-write, does VirtualQuery return MEM_PRIVATE?
No. A data view stays MEM_MAPPED and an image view stays MEM_IMAGE. To find out whether a page has actually been privatized, make the page resident and then look at the Shared bit from QueryWorkingSetEx.
May I store raw pointers in shared memory?
Usually you should avoid it. Even for the same section, there is no guarantee that each process's view is placed at the same virtual address. In a shared structure, use offsets from the base, fixed-width integers, and an explicit layout and synchronization scheme.

Author Profile

Profile page for the article author.

Go Komura

Representative of KomuraSoft LLC

Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.

Back to the Blog