The Depths of Windows Memory (Part 3) — Section Objects and Copy-on-Write: What DLLs and File Mappings Really Are
· Go Komura · Windows, Memory Management, Shared Memory, File Mapping, Copy-on-Write, DLL, Cache Manager
In the previous article, “The Depths of Windows Memory (Part 2) — The Life of a Physical Page”, we followed how a physical page that leaves the Working Set moves through Modified, Standby, Free, and Zeroed. That Standby also holds pages from DLLs, EXEs, mapped files, and the file cache.
A question arises here. When 100 processes use the same kernel32.dll, does Windows put 100 sets of code pages in RAM? When two processes memory-map the same file, can the other use a page that one of them read?
The answer is mapping multiple virtual addresses onto the same physical page. The center that represents that unit of sharing is the section object, and the mechanism that splits the sharing only at write time is copy-on-write (CoW).
This article follows how EXEs and DLLs, data files, pagefile-backed shared memory, and the file cache attach to the same file stream, and where the processing paths diverge. The reading of the numbers themselves takes the introductory article “What Does Windows’ “Memory Usage” Actually Mean?” as a given.
“The Depths of Windows Memory” — All 3 Parts
- Part 1: Virtual Addresses and Page Faults
We follow the moment a committed virtual page obtains physical RAM. - Part 2: The Life of a Physical Page
We follow the state transitions of a page that leaves the Working Set. - Part 3 (this article): Section Objects and Copy-on-Write
We follow the mechanism by which DLLs, file mappings, and shared memory share physical pages.
The question Part 3 answers is just one.
Why can multiple processes use the same DLL or file as one set of physical pages?
Intended readers are developers and operators who want to understand DLL sharing, CreateFileMapping, MapViewOfFile, shared memory, CoW, and the relationship to the file cache not only as API usage but from the internal structure. Prerequisites are Windows 10/11 or current Windows Server, and required background is the basics of virtual addresses, page faults, and the Working Set. The difficulty is intermediate; we also use internal terms such as Control Area and Prototype PTE, but the observations can be reproduced with VMMap, Process Explorer, and QueryWorkingSetEx.
1. The Bottom Line First
To start, here is the overall picture.
- A section object represents a shareable memory range.
Each process maps part of that section into its own virtual space as a “view”.1 - Views of the same section need not be at the same virtual address.
Process A’s0x000001...and process B’s0x000002...can point at the same section offset and the same physical page.2 - There are file-backed and pagefile-backed sections.
The former uses a real file; the latter is used for shared memory that has no explicit file, and the like.2 - Loading an EXE/DLL is an image section; ordinary file mapping is a data section.
WithSEC_IMAGE, section attributes inside the PE determine page protection.3 - During reads the same physical page can be shared.
When one side writes to a CoW page, only that page is copied and the writing process’s PTE is swapped.4 - Even on the same file stream, the cache, data, and image paths diverge.
Cache Manager cached I/O usesSharedCacheMap, data mapping usesDataSectionObject, and EXEs/DLLs useImageSectionObject. The three attach to the same file stream throughSECTION_OBJECT_POINTERS, but an image fault does not go through the Cache Manager.5 - Private Bytes alone cannot confirm that CoW occurred.
FILE_MAP_COPYcharges Commit for the entire view up front, against the possibility that every page will later be privatized. For a per-page check, use the Shared bit fromQueryWorkingSetEx.67
In one sentence: what is shared is not the virtual address, but the contents inside the section and the physical page that corresponds at that moment.
2. Section Objects and Views
In Microsoft’s definition, a section object represents a shareable region of memory and is also the mechanism that maps a file into a process’s address space.1
The trick to understanding it is to separate the section itself from the view each process sees.
| Concept | Role |
|---|---|
| Section object | Represents the contents to share, the size, the backing store, and the protection ceiling |
| View | Shows part of the section as a virtual address range in some process |
| PTE | Binds each virtual page in the view to the current physical page or an unrealized state |
| PFN | Represents a physical page that actually exists in RAM |
In Win32, CreateFileMapping returns a handle to a file-mapping object, and MapViewOfFile creates a view in the process’s virtual space.3
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 you an address the process can read. Further, creating a view does not put every page into RAM immediately. From the first page that is touched, a page fault reads the file contents and binds a physical page to the PTE.8 In other words, the demand paging we saw in Part 1 applies to section views as well.
2.1. The Same Section, Different Virtual Addresses
Even when process A and process B map the same offset of the same section, the view’s start address can differ.
flowchart LR
accTitle: Mapping different virtual addresses onto the same physical page
accDescr: Process A and process B each have a view at a different virtual address, but they reach the same physical page PFN X through the same section offset
viewA["Process A: 0x000001A00000 + 0x3000"] --> offset["Section offset 0x3000"]
viewB["Process B: 0x000002700000 + 0x3000"] --> offset
offset --> pfnX["The same physical page PFN X"]
Figure 1: What is shared is the contents inside the section and the physical page, not the virtual address.
That is why you must not store a raw pointer in shared memory. Process A’s pointer value may be an unrelated address in process B.
In a shared structure, use an offset from the start of the view, fixed-width integers, and an explicit version and alignment. Microsoft’s MapViewOfFileEx documentation also recommends storing an offset from the base rather than a pointer, because there is no guarantee that the same address will be available in the future.6
3. File-Backed and Pagefile-Backed
Sections split into two large kinds according to where the contents can be restored from.
flowchart TB
accTitle: How file-backed and pagefile-backed diverge
accDescr: Passing a real file to CreateFileMapping produces a file-backed section, and a clean page can be re-read from the original file. Passing INVALID_HANDLE_VALUE produces a pagefile-backed section; the page file backs the contents, which disappear when the object is destroyed
create["CreateFileMapping"] -->|Pass a real-file handle| fileBacked["File-backed section"]
create -->|Pass INVALID_HANDLE_VALUE| pfBacked["Pagefile-backed section"]
fileBacked --> restore1["A clean page can be re-read from the original file"]
pfBacked --> restore2["The page file backs the contents, which disappear on destroy"]
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 needed pages from the file.
- Changes to a read/write view are treated as data of that file.
- Changes to 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. That 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 CreateFileMapping’s hFile 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 is a section with no explicit data file, backed by the page file. The initial contents are zero, and multiple processes can open the same object through a name, handle inheritance, DuplicateHandle, and the like.93 Changes are visible to processes that map the same shared page. On the other hand, when the section object is destroyed the contents do not remain, so it is not suited to leaving a persistent file.2
A caution: shared memory does not automatically come with mutual exclusion. You design a mutex, semaphore, event, lock-free protocol, or similar 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.
| Item | Image mapping | Data mapping |
|---|---|---|
| Main use | Loading an EXE or DLL | Ordinary files, shared data |
| Creation attribute | SEC_IMAGE |
PAGE_READONLY, PAGE_READWRITE, and the like |
| Page protection | Attributes inside the PE image decide | The mapping and view specification decide |
| Writes | Can be privatized via a writable section or CoW | Shared write or CoW can be chosen |
VirtualQuery Type |
MEM_IMAGE |
MEM_MAPPED |
With SEC_IMAGE, the executing image’s own section attributes decide the view’s page protection, more than the ordinary protection value passed to CreateFileMapping.3
Through this mechanism, unmodified pages such as code can share the same physical page across many processes, and only pages that need a process-private change branch via CoW. That said, not every DLL page is necessarily shared — because of ASLR relocation, loader fixes, hotpatching, the actual PE section attributes, and so on.
The important design is share shareable pages first, and lazily copy only the pages that need a change.
5. Copy-on-Write from Start to Finish
Let us follow from the state where two processes are reading the same CoW page through to Process A writing one byte.
5.1. Before the Write
Before a write occurs, both processes’ PTEs conceptually reach the same shared page, and reads succeed as-is.
flowchart LR
accTitle: Shared state before copy-on-write
accDescr: Before a write occurs, process A's PTE and process B's PTE both reach the same shared page PFN X, and reads succeed as-is
pteA["Process A PTE"] --> pfnX["Shared PFN X (read / copy-on-write)"]
pteB["Process B PTE"] --> pfnX
Figure 3: Before the write, both processes’ PTEs point at the same physical page.
5.2. A Protection Fault on Write
A CoW page is not an ordinary shared writable page from the start. When Process A tries to write, the CPU raises a protection fault. The memory manager that receives control judges that this is not an illegal write but a write to a CoW attribute.
5.3. Creating a New Physical Page
On that judgment, Windows does the following.
- Obtain one physical page for Process A.
- Copy the contents of PFN X to the new page PFN Y.
- Swap Process A’s PTE to PFN Y.
- Change Process A’s protection to ordinary read/write.
- Re-execute the write instruction that failed.
flowchart LR
accTitle: Split state after copy-on-write
accDescr: After 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 continues to point at the original shared page PFN X
pteA2["Process A PTE"] --> pfnY["Private PFN Y (R/W, after write)"]
pteB2["Process B PTE"] --> pfnX2["Shared PFN X (original)"]
pfnX2 -.->|Copied at write| pfnY
Figure 4: Only the writing process’s PTE is swapped to a new private page; the other side continues to read the original contents.
Process B continues to read the original contents and does not see Process A’s change. That is Copy-on-Write. DLL sharing and FILE_MAP_COPY both use the same principle: do not copy until you write.46
5.4. The Difference from FILE_MAP_WRITE
A page written through shared write with FILE_MAP_WRITE is designed so that one side’s change is also visible from another view that uses the same file mapping. With FILE_MAP_COPY, by contrast, 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.6
Do you want “to communicate an update through shared memory”, or “each process to make private changes from common initial data”? The right choice is the opposite depending on the purpose.
6. After CoW It Remains MEM_MAPPED / MEM_IMAGE
A page after CoW has become physically Private. You might then expect VirtualQuery’s Type to change to MEM_PRIVATE as well, but in fact a data view remains MEM_MAPPED and an executable image remains MEM_IMAGE. VirtualQuery reports which initial allocation the region came from.7
To see per page whether CoW has already occurred, use the following procedure.
- Access the target page and make it resident.
- Obtain the page’s Working Set information with
QueryWorkingSetEx. - Look at the
Sharedbit. - If
Shared == 0, that resident page is Private.
When confirming 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
With FILE_MAP_COPY, the process may later write to every page in the view. So Windows takes a Commit charge equivalent to the entire view at map time.6 As a result, writing the first page does not necessarily increase Private Bytes by 4KiB at that instant.
The metrics to prefer when observing CoW are the following.
- The Shared bit from
QueryWorkingSetEx - VMMap’s Private WS / Shareable WS
- RAMMap’s physical-page information
- Private Bytes as supplementary information
If you treat “did Private Bytes increase at the moment of the write” as the pass/fail test, you will miss CoW that is working correctly.
7. The Contact Point with the Cache Manager — 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 SECTION_OBJECT_POINTERS, used by the memory manager and the Cache Manager.
typedef struct _SECTION_OBJECT_POINTERS {
PVOID DataSectionObject;
PVOID SharedCacheMap;
PVOID ImageSectionObject;
} SECTION_OBJECT_POINTERS;
DataSectionObject: section state for a data fileSharedCacheMap: the cache view the Cache Manager tracksImageSectionObject: section state for an executable image
Microsoft’s documentation explains that this structure binds a file object to the file stream’s sections and tracks in-memory contents and cache information.5
Here the I/O series and the memory series connect. Keep the three paths separate as you understand them, though.
- Cached
ReadFile/WriteFileuses the Cache Manager’sSharedCacheMapand cache view. - A mapping fault on a data file is handled by the memory manager on the
DataSectionObjectside. It cooperates with cached I/O on the same file stream to keep the contents consistent. - An image fault on an EXE/DLL is handled by the memory manager with
ImageSectionObjectand paging I/O. It is not a path that goes through the Cache Manager’sSharedCacheMap.
flowchart TB
accTitle: Three paths that attach to the same file stream
accDescr: Cached ReadFile/WriteFile uses SharedCacheMap, a data-mapping fault uses DataSectionObject, and an EXE/DLL image fault uses ImageSectionObject; the three attach to the same file stream through SECTION_OBJECT_POINTERS
cached["Cached ReadFile / WriteFile"] --> scm["SharedCacheMap"]
dataFault["Data-mapping fault"] --> dso["DataSectionObject"]
imageFault["EXE/DLL image fault"] --> iso["ImageSectionObject"]
scm --> stream["The same file stream (SECTION_OBJECT_POINTERS)"]
dso --> stream
iso --> stream
Figure 5: The three paths are processed separately, but they attach on the same file stream.
What the three have in common is not that “everything enters the Cache Manager”, but that the same file stream binds separate states — cache, data section, and image section — through SECTION_OBJECT_POINTERS.5 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 you mix a memory-mapped view with ReadFile/WriteFile, you are not guaranteed to always see the contents of the same instant. The design needs to include synchronization, flush, and the file-sharing mode.36
8. Lifetime of the Object and the View
Closing the CreateFileMapping handle alone does not destroy an existing view. A view holds an internal reference to the section, and only after every view is UnmapViewOfFile‘d and every handle is CloseHandle‘d does the object become destroyable.3
UnmapViewOfFile(view);
CloseHandle(mapping);
CloseHandle(file);
This separation of lifetimes is a cause of the phenomenon “I closed the file, but it is still in use”. Even after you close the file handle, if an image section or a data view still refers to the file stream, the file’s final close comes later.
The relationship to cleanup/close on the I/O side is covered in “The Depths of Windows I/O (Part 1)”, and implementation pitfalls are covered in “Shared Memory Pitfalls and Practical Best Practices”.
9. See It for Yourself
9.1. Looking at the Same DLL from Two Processes
First, confirm DLL sharing with existing processes.
- Start Process Explorer as administrator.
- Start two
cmd.exeprocesses. - Choose View > Lower Pane View > DLLs.
- Confirm the path and mapping of the same DLL in both processes.
- Open each
cmd.exein VMMap and compare Images Working Set, Private, and Shareable.
Seeing the same DLL in Process Explorer is evidence that both have mapped the same image. That alone, however, does not prove that each page’s PFN matches. Combine VMMap’s Shareable breakdown, RAMMap, and QueryWorkingSetEx to confirm per-page sharing. Process Explorer and VMMap are provided by Sysinternals.1011
9.2. Observing FILE_MAP_COPY from Two Processes
The following program maps the same file as a CoW view and displays 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 causes 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 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
After starting both, press Enter first on the read side and then on the write side, and confirm that Shared is set in before on both. Press Enter once more on the write side and that process’s page becomes Shared 0. Then press Enter on the read side and you can confirm that the reader continues to read the original page. VirtualQuery’s Type remains MEM_MAPPED after the write as well.
Note that PrintPage re-touches the target page immediately before querying, and if Valid == 0 it does not interpret Shared and ShareCount and retries up to three times. If the page is still not resident it does not produce a result and reports that. ShareCount can change with timing and memory pressure, so look at the change in the Shared bit confirmed at 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 page. The view’s virtual address can differ per process, so store an offset rather than a raw pointer.
10.2. “If it is the same DLL, every page is necessarily shared”
Clean code pages are easy to share, while relocation, a writable section, CoW, and the residency at the moment of measurement also produce Private pages.
10.3. “After CoW it becomes MEM_PRIVATE”
VirtualQuery’s Type remains 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. Prefer Private WS and the Shared bit.6
10.5. “If the page is shared, synchronization is unnecessary”
Seeing the same physical page and being able to update it safely from multiple CPU cores are different problems. Design atomicity, memory ordering, mutual exclusion, intermediate state at crash time, and version compatibility.
The idea of following references and lifetime separately also applies to the problem of a process remaining after Excel COM interop. See also “Why EXCEL.EXE Processes Remain After C# Excel COM Automation”.
11. Summary
- A section object represents a shareable memory range, and each process maps it into its own virtual 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 supports a real file; a pagefile-backed section supports named shared memory and the like.9
- An EXE/DLL is treated as an image section and an ordinary file as a data section; protection and the write-back destination differ.3
- CoW shares the physical page during reads and, on the first write, copies only that page and swaps the PTE.4
- After CoW,
VirtualQuerystill returnsMEM_MAPPED/MEM_IMAGE, so you confirm with the Shared bit fromQueryWorkingSetEx.7 - With
FILE_MAP_COPY, Commit for the entire view is charged first, so you cannot judge CoW from Private Bytes alone.6 - Cache Manager cached I/O, data mapping, and image mapping attach on the same file stream as separate paths that use
SharedCacheMap,DataSectionObject, andImageSectionObjectrespectively.5 - Shared memory becomes safe only when you include the lifetime of views and handles, synchronization, ACLs, and offset design.
That completes all three parts of “The Depths of Windows Memory”. You Reserve/Commit a virtual address, obtain a physical page through a page fault, move the page from the Working Set onto a page list, share it through a section, and split only the pages you wrote via CoW — Windows memory management is connected as this single flow.
Related Articles
- The Depths of Windows Memory (Part 1) — The Moment a Virtual Address Becomes Physical RAM: A Page Fault from Start to Finish
- The Depths of Windows Memory (Part 2) — The Life of a Physical Page: Five Lists and the Truth About the Page File
- The Depths of Windows I/O (Part 4) — Cache Manager: When Does Your WriteFile Actually Reach the Disk?
- Shared Memory Pitfalls and Practical Best Practices
- Why EXCEL.EXE Processes Remain After C# Excel COM Automation — Reference Release Patterns and the Replacement Decision
- Process Explorer / Handle / VMMap in Practice — Chasing Hangs, Leaks, and “File in Use” from the State Right Now
Related Consulting Areas
KomuraSoft LLC handles defect investigations of Windows application shared memory, file mapping, DLL loading, file locking, inter-process communication, and memory usage.
- Windows Application Development
- Bug Investigation & Root-Cause Analysis
- Legacy Asset Migration
- Contact Us
References
-
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
-
Microsoft Learn, File-Backed and Page-File-Backed Sections. On file-backed and pagefile-backed sections, CoW, and being able to share the same physical memory from different processes’ virtual addresses. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, CreateFileMappingW function. On the file-mapping object, pagefile-backed sections,
SEC_IMAGE, the lifetime of views and handles, and consistency among views that back the same file. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, Memory Protection. On multiple processes sharing the same DLL’s physical pages, and CoW copying to a new physical page and updating the PTE when one side writes. ↩ ↩2 ↩3
-
Microsoft Learn, SECTION_OBJECT_POINTERS structure. On DataSectionObject, SharedCacheMap, and ImageSectionObject binding a file stream’s mapping and cache information to the memory manager / Cache Manager. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, MapViewOfFileEx function. On CoW with
FILE_MAP_COPY; private pages being backed by the page file; charging Commit for the entire view; and storing an offset rather than a virtual address. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, VirtualQuery function. On Type remaining
MEM_MAPPED/MEM_IMAGEafter CoW, and being able to confirm privatization with the Shared bit fromQueryWorkingSetEx. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Managing Memory Sections. On physical memory not being assigned until the view is accessed, and the first-access page fault reading the file contents. ↩
-
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 -
Microsoft Learn, Process Explorer - Sysinternals. On Process Explorer being able to display a process’s handles and loaded DLLs / memory-mapped files. ↩
-
Microsoft Learn, VMMap - Sysinternals. On VMMap breaking down a process’s virtual memory into Image, Mapped File, Private, and the like, and displaying the Private/Shareable breakdown of the Working Set. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
DllMain and the Loader Lock — The Real Reason You're Told to "Do Nothing in DLL Initialization"
Why you must not call LoadLibrary or synchronize with other threads from DllMain. Drawing on primary sources, this article explains how t...
The Depths of Windows Memory (Part 2) — The Life of a Physical Page: Five Lists and the Truth About the Page File
This article connects the PFN database, Standby, Modified, memory compression, and the page file to explain where a physical page goes af...
The Depths of Windows Memory (Part 1) — The Moment a Virtual Address Becomes Physical RAM: A Page Fault from Start to Finish
This article connects VirtualAlloc, VADs, page tables, the TLB, demand-zero faults, and hard faults to explain the moment a virtual addre...
What Does Windows' "Memory Usage" Actually Mean? — Correctly Reading Working Set, Private Bytes, Commit, and the Page File
Task Manager's Memory, Working Set, Private Bytes, and Commit are not the same figure. This article explains the relationship between Win...
Choosing Windows Inter-Process Communication ── A Decision Table for Named Pipes / TCP / gRPC / Shared Memory / COM
How do you choose the right way for Windows applications to talk to each other? This article organizes named pipes, local TCP, gRPC, shar...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
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 it does not. Unmodified pages of the same image are mapped from each process's different virtual addresses onto the same physical page. Only pages that need a write become process-private physical pages, through copy-on-write and the like.
- 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 space. Further, the view's physical pages are normally materialized by a page fault from 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 reflected on the shared file-data side. 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?
- It does not. A data view remains MEM_MAPPED and an image view remains MEM_IMAGE. To see whether a page has actually been privatized, make the page resident and look at the Shared bit from QueryWorkingSetEx.
- May you store a raw pointer in shared memory?
- Usually you should not. Even with 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.