संशोधन इतिहास (पहला संस्करण, 20 Aug 2026 को प्रकाशित)
- पहला प्रकाशन
इस लेख का हवाला दें(DOI: 10.5281/zenodo.22176182)
यह लेख Zenodo पर संग्रहीत है। नीचे वह DOI है जो हमेशा नवीनतम संस्करण की ओर ले जाता है, और वह DOI भी जो आपके पढ़े जा रहे संस्करण से बँधा है।
Go Komura (2026). Windows मेमोरी की गहराई (भाग 3) — Section object और copy-on-write: DLL और file mapping वास्तव में क्या हैं. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22176182 https://comcomponent.com/hi/blog/windows-memory-internals-section-copy-on-write/
- DOI (नवीनतम संस्करण)
- 10.5281/zenodo.22176182
- DOI (यह संस्करण)
- 10.5281/zenodo.22176183
पिछले लेख «Windows मेमोरी की गहराई (भाग 2) — एक physical page का जीवन» में हमने देखा कि Working Set छोड़ने वाला physical page Modified, Standby, Free और Zeroed से कैसे गुज़रता है। उसी Standby में DLL, EXE, mapped फ़ाइलें और file cache के pages भी रहते हैं।
यहाँ एक प्रश्न उठता है। जब 100 processes एक ही kernel32.dll इस्तेमाल करते हैं, क्या Windows RAM में code pages के 100 सेट रखता है? जब दो processes एक ही फ़ाइल को memory-map करते हैं, क्या दूसरा उस page का उपयोग कर सकता है जिसे एक ने पढ़ा?
उत्तर है कई virtual addresses को एक ही physical page पर map करना। उस sharing इकाई का केंद्र section object है, और लिखने के समय ही sharing तोड़ने वाला mechanism copy-on-write (Copy-on-Write, CoW) है।
यह लेख देखता है कि EXE और DLL, data फ़ाइलें, pagefile-backed shared memory और file cache एक ही file stream से कैसे जुड़ते हैं, और processing path कहाँ बँटते हैं। संख्याएँ पढ़ना स्वयं परिचयात्मक लेख «What Does Windows’ “Memory Usage” Actually Mean?» को आधार मानता है।
«Windows मेमोरी की गहराई» — तीनों भाग
- भाग 1: Virtual addresses और page fault
हम उस क्षण का अनुसरण करते हैं जब Commit किया गया virtual page physical RAM पाता है। - भाग 2: एक physical page का जीवन
हम Working Set छोड़ने वाले page की state-changes का अनुसरण करते हैं। - भाग 3 (यह लेख): Section object और copy-on-write
हम उस mechanism का अनुसरण करते हैं जिससे DLL, file mapping और shared memory physical pages share करते हैं।
भाग 3 जिस प्रश्न का उत्तर देता है वह केवल एक है।
कई processes एक ही DLL या फ़ाइल को physical pages के एक सेट के रूप में क्यों इस्तेमाल कर सकते हैं?
लक्षित पाठक वे developers और operators हैं जो DLL sharing, CreateFileMapping, MapViewOfFile, shared memory, CoW और file cache से संबंध को केवल API उपयोग नहीं बल्कि internal structure से समझना चाहते हैं। पूर्वापेक्षाएँ Windows 10/11 या वर्तमान Windows Server हैं, और आवश्यक background virtual addresses, page fault और Working Set की बुनियाद है। कठिनाई मध्यम है; हम Control Area और Prototype PTE जैसे internal शब्द भी इस्तेमाल करते हैं, लेकिन अवलोकन VMMap, Process Explorer और QueryWorkingSetEx से दोहराए जा सकते हैं।
1. पहले निष्कर्ष
शुरुआत में पूरी तस्वीर।
- Section object share करने योग्य memory range दर्शाता है।
हर process उस section का भाग अपने virtual space में «view» के रूप में map करता है।1 - एक ही section के views एक ही virtual address पर होने आवश्यक नहीं।
Process A का0x000001...और process B का0x000002...एक ही section offset और एक ही physical page की ओर इशारा कर सकते हैं।2 - File-backed और pagefile-backed sections होते हैं।
पहले वास्तविक फ़ाइल इस्तेमाल करते हैं; दूसरे स्पष्ट फ़ाइल के बिना shared memory आदि के लिए।2 - EXE/DLL load करना image section है; साधारण file mapping data section है।
SEC_IMAGEके साथ PE के अंदर section attributes page protection तय करते हैं।3 - पढ़ते समय एक ही physical page share हो सकता है।
जब एक पक्ष CoW page पर लिखता है, केवल वही page कॉपी होता है और लिखने वाले process का PTE बदल जाता है।4 - एक ही file stream पर भी cache, data और image paths अलग होते हैं।
Cache Manager का cached I/OSharedCacheMapइस्तेमाल करता है, data mappingDataSectionObject, और EXE/DLLImageSectionObject। तीनोंSECTION_OBJECT_POINTERSसे एक ही stream से जुड़ते हैं, लेकिन image fault Cache Manager से नहीं जाता।5 - अकेले Private Bytes यह पुष्टि नहीं कर सकते कि CoW हुआ।
FILE_MAP_COPYmap के समय पूरे view का Commit पहले ही लगाता है, इस आशंका से कि बाद में हर page private हो जाए। Per-page जाँच के लिएQueryWorkingSetExका Shared bit इस्तेमाल करें।67
एक वाक्य में: Share virtual address नहीं, बल्कि section के अंदर की content और उस क्षण का matching physical page है।
2. Section object और view
Microsoft की परिभाषा में section object share करने योग्य memory क्षेत्र दर्शाता है और वह mechanism भी है जो फ़ाइल को process के address space में map करता है।1
समझने की कुंजी section को उस view से अलग करना है जो हर process देखता है।
| अवधारणा | भूमिका |
|---|---|
| Section object | Share करने की content, आकार, backing store और protection की ऊपरी सीमा दर्शाता है |
| View | Section का भाग किसी process में virtual address range के रूप में दिखाता है |
| PTE | View के हर virtual page को वर्तमान physical page या unrealized अवस्था से बाँधता है |
| PFN | वह physical page दर्शाता है जो वास्तव में RAM में मौजूद है |
Win32 में CreateFileMapping file-mapping object का handle लौटाता है, और MapViewOfFile process के virtual space में view बनाता है।3
HANDLE mapping = CreateFileMappingW(
file,
nullptr,
PAGE_READONLY,
0,
0,
nullptr);
void* view = MapViewOfFile(
mapping,
FILE_MAP_READ,
0,
0,
0);
केवल CreateFileMapping बुलाने से process को पढ़ने योग्य address अभी नहीं मिलता। View बनाना भी हर page तुरंत RAM में नहीं डालता। पहले छुए गए page से page fault फ़ाइल content पढ़ता है और PTE से physical page बाँधता है।8 अर्थात् भाग 1 का demand paging section view पर भी लागू होता है।
2.1. एक ही section, अलग virtual addresses
भले process A और process B एक ही section का एक ही offset map करें, view का प्रारंभ address भिन्न हो सकता है।
flowchart LR
accTitle: अलग virtual addresses को एक ही physical page पर map करना
accDescr: Process A और process B प्रत्येक के पास अलग virtual address पर view है, लेकिन वे एक ही section offset से एक ही physical page PFN X तक पहुँचते हैं
viewA["Process A: 0x000001A00000 + 0x3000"] --> offset["Section offset 0x3000"]
viewB["Process B: 0x000002700000 + 0x3000"] --> offset
offset --> pfnX["एक ही physical page PFN X"]
चित्र 1: Share section के अंदर की content और physical page है, virtual address नहीं।
इसीलिए shared memory में raw pointer न रखें। Process A का pointer मान process B में unrelated address हो सकता है।
Shared structure में view के प्रारंभ से offset, fixed-width integers, तथा स्पष्ट version और alignment इस्तेमाल करें। Microsoft का MapViewOfFileEx document भी pointers के बजाय base से offsets रखने की सलाह देता है, क्योंकि भविष्य में वही address उपलब्ध रहे इसकी गारंटी नहीं।6
3. File-backed और pagefile-backed
Sections इस आधार पर दो बड़े प्रकारों में बँटते हैं कि content कहाँ से restore हो सकती है।
flowchart TB
accTitle: File-backed और pagefile-backed कैसे बँटते हैं
accDescr: CreateFileMapping को वास्तविक फ़ाइल देने से file-backed section बनता है, और clean page मूल फ़ाइल से फिर पढ़ा जा सकता है। INVALID_HANDLE_VALUE देने से pagefile-backed section बनता है; page file content थामती है, जो object नष्ट होने पर गायब हो जाती है
create["CreateFileMapping"] -->|वास्तविक फ़ाइल handle दें| fileBacked["File-backed section"]
create -->|INVALID_HANDLE_VALUE दें| pfBacked["Pagefile-backed section"]
fileBacked --> restore1["Clean page मूल फ़ाइल से फिर पढ़ा जा सकता है"]
pfBacked --> restore2["Page file content थामती है, जो नष्ट होने पर गायब होती है"]
चित्र 2: Backing store का अंतर तय करता है कि content कहाँ से लौटे और कितनी देर जिए।
3.1. File-backed section
CreateFileMapping को वास्तविक फ़ाइल देने से file-backed section बनता है।
- Read-only view आवश्यक pages फ़ाइल से पढ़ता है।
- Read/write view के बदलाव उस फ़ाइल के data माने जाते हैं।
- CoW view के बदलाव मूल फ़ाइल में नहीं लिखे जाते; वे private pages बन जाते हैं।
अगर file-backed page clean है, physical page त्यागा जा सकता है और मूल फ़ाइल से फिर पढ़ा जा सकता है। यही गुण भाग 2 में देखी Standby और file cache की दक्षता थामता है।
3.2. Pagefile-backed section
CreateFileMapping के hFile में INVALID_HANDLE_VALUE देना और आकार बताना pagefile-backed section बनाता है।
HANDLE mapping = CreateFileMappingW(
INVALID_HANDLE_VALUE,
nullptr,
PAGE_READWRITE,
0,
64 * 1024,
L"Local\\KomuraMemoryDemo");
यह स्पष्ट data फ़ाइल के बिना section है, जिसे page file थामती है। प्रारंभिक content शून्य है, और कई processes नाम, handle inheritance, DuplicateHandle आदि से एक ही object खोल सकते हैं।93 बदलाव उसी shared page को map करने वाले processes को दिखते हैं। दूसरी ओर, section object नष्ट होने पर content नहीं रहती, इसलिए स्थायी फ़ाइल छोड़ने के लिए उपयुक्त नहीं।2
सावधानी: Shared memory अपने आप mutual exclusion नहीं लाती। Mutex, semaphore, event, lock-free protocol आदि अलग से डिज़ाइन करें।9
4. Image mapping और data mapping
जब हम कहते हैं «EXE या DLL भी file mapping है», साधारण data फ़ाइल से अंतर फिर भी रखना चाहिए।
| मद | Image mapping | Data mapping |
|---|---|---|
| मुख्य उपयोग | EXE या DLL load करना | साधारण फ़ाइलें, shared data |
| निर्माण विशेषता | SEC_IMAGE |
PAGE_READONLY, PAGE_READWRITE आदि |
| Page protection | PE image के अंदर attributes तय करती हैं | Mapping और view specification तय करते हैं |
| लेखन | Writable section या CoW से private किया जा सकता है | Shared write या CoW चुना जा सकता है |
VirtualQuery Type |
MEM_IMAGE |
MEM_MAPPED |
SEC_IMAGE के साथ view की page protection मुख्यतः executed image की अपनी section attributes तय करती हैं, न कि CreateFileMapping को दिए साधारण protection मान।3
इस mechanism से code जैसे unmodified pages कई processes में एक ही physical page share कर सकते हैं, और केवल process-private बदलाव वाले pages CoW से शाखा लेते हैं। फिर भी हर DLL page आवश्यक रूप से share नहीं होता — ASLR relocation, loader fixes, hotpatch, वास्तविक PE section attributes आदि के कारण।
महत्वपूर्ण डिज़ाइन है पहले share करने योग्य pages share करें, और केवल बदलाव वाले pages देर से कॉपी करें।
5. Copy-on-write शुरू से अंत तक
दो processes एक ही CoW page पढ़ रहे हों, उस अवस्था से process A के एक byte लिखने तक चलें।
5.1. लिखने से पहले
लेखन होने से पहले दोनों processes के PTE अवधारणात्मक रूप से एक ही shared page तक पहुँचते हैं, और पठन वैसे ही सफल होता है।
flowchart LR
accTitle: Copy-on-write से पहले की shared अवस्था
accDescr: लेखन होने से पहले process A का PTE और process B का PTE दोनों एक ही shared page PFN X तक पहुँचते हैं, और पठन वैसे ही सफल होता है
pteA["Process A PTE"] --> pfnX["Shared PFN X(read / copy-on-write)"]
pteB["Process B PTE"] --> pfnX
चित्र 3: लिखने से पहले दोनों processes के PTE एक ही physical page की ओर इशारा करते हैं।
5.2. लिखते समय protection fault
CoW page शुरू से साधारण shared writable page नहीं होता। जब process A लिखने का प्रयास करता है, CPU protection fault उठाता है। नियंत्रण पाने वाला memory manager तय करता है कि यह अवैध लेखन नहीं बल्कि CoW attribute पर लेखन है।
5.3. नया physical page बनाना
उस निर्णय पर Windows यह करता है।
- Process A के लिए एक physical page प्राप्त करें।
- PFN X की content नए page PFN Y पर कॉपी करें।
- Process A का PTE PFN Y से बदलें।
- Process A की protection साधारण read/write करें।
- असफल लिखने के instruction को फिर चलाएँ।
flowchart LR
accTitle: Copy-on-write के बाद की विभाजित अवस्था
accDescr: Process A की लेखन के बाद केवल process A का PTE उस private page PFN Y से बदला जाता है जिसे content की कॉपी मिली, जबकि process B का PTE मूल shared page PFN X की ओर इशारा करता रहता है
pteA2["Process A PTE"] --> pfnY["Private PFN Y(R/W, लिखने के बाद)"]
pteB2["Process B PTE"] --> pfnX2["Shared PFN X(मूल)"]
pfnX2 -.->|लिखते समय कॉपी| pfnY
चित्र 4: केवल लिखने वाले process का PTE नए private page से बदला जाता है; दूसरा पक्ष मूल content पढ़ता रहता है।
Process B मूल content पढ़ता रहता है और process A का बदलाव नहीं देखता। यही Copy-on-Write है। DLL sharing और FILE_MAP_COPY एक ही सिद्धांत इस्तेमाल करते हैं: जब तक लिखें नहीं, कॉपी न करें।46
5.4. FILE_MAP_WRITE से अंतर
FILE_MAP_WRITE की shared लिखत से लिखा page इस तरह डिज़ाइन है कि एक पक्ष का बदलाव उसी file mapping वाले दूसरे view से भी दिखे। FILE_MAP_COPY में इसके विपरीत केवल लिखे गए pages process-private होते हैं; बदलाव मूल फ़ाइल में वापस नहीं लिखे जाते और view unmap होते ही खो जाते हैं।6
क्या आप चाहते हैं «shared memory से update पहुँचाना», या «हर process shared प्रारंभिक data से private बदलाव करे»? उद्देश्य के अनुसार सही चुनाव उलटा होता है।
6. CoW के बाद भी MEM_MAPPED / MEM_IMAGE
CoW के बाद page physically Private हो चुका है। तब लगता है VirtualQuery का Type भी MEM_PRIVATE हो जाएगा, लेकिन वास्तव में data view MEM_MAPPED और executable image MEM_IMAGE रहता है। VirtualQuery बताता है कि क्षेत्र किस प्रारंभिक allocation से आया।7
Per page यह देखने के लिए कि CoW पहले ही हुआ या नहीं, यह procedure इस्तेमाल करें।
- Target page तक पहुँचें और उसे resident बनाएँ।
QueryWorkingSetExसे page की Working Set जानकारी लें।Sharedbit देखें।- अगर
Shared == 0तो वह resident page Private है।
VMMap में पुष्टि करते समय भी केवल क्षेत्र के Type नहीं, Working Set के Private/Shareable विभाजन देखें।
6.1. Private Bytes बढ़ें नहीं भी सकते
FILE_MAP_COPY में process बाद में view के हर page पर लिख सकता है। इसलिए Windows map के समय पूरे view के बराबर Commit charge लेता है।6 परिणामस्वरूप पहला page लिखने पर उसी क्षण Private Bytes 4KiB नहीं बढ़ सकते।
CoW देखते समय ये metrics प्राथमिकता दें।
QueryWorkingSetExका Shared bit- VMMap का Private WS / Shareable WS
- RAMMap की physical-page जानकारी
- पूरक जानकारी के रूप में Private Bytes
अगर «लिखने के क्षण Private Bytes बढ़े या नहीं» को pass/fail परीक्षा मानें, तो सही काम कर रहे CoW छूट जाएँगे।
7. Cache Manager से संपर्क — तीन paths अलग रखें
«EXE/DLL load, file cache और shared memory सब sections हैं» कहना पूरी तस्वीर देता है, लेकिन implementation को एक object में न समेटें।
File stream के पास SECTION_OBJECT_POINTERS होते हैं, जिन्हें memory manager और Cache Manager इस्तेमाल करते हैं।
typedef struct _SECTION_OBJECT_POINTERS {
PVOID DataSectionObject;
PVOID SharedCacheMap;
PVOID ImageSectionObject;
} SECTION_OBJECT_POINTERS;
DataSectionObject: Data फ़ाइल की section अवस्थाSharedCacheMap: Cache Manager द्वारा track किया गया cache viewImageSectionObject: Executable image की section अवस्था
Microsoft document बताता है कि यह structure file object को file stream के section से बाँधती है और memory में content तथा cache जानकारी track करती है।5
यहाँ I/O श्रृंखला और memory श्रृंखला मिलती हैं। फिर भी तीन paths अलग समझें।
- Cached
ReadFile/WriteFileCache Manager केSharedCacheMapऔर cache view इस्तेमाल करते हैं। - Data फ़ाइल पर mapping fault memory manager
DataSectionObjectपक्ष पर संभालता है। वह उसी stream के cached I/O से सहयोग कर content consistent रखता है। - EXE/DLL पर image fault memory manager
ImageSectionObjectऔर paging I/O से संभालता है। यह Cache Manager केSharedCacheMapसे जाने वाला path नहीं।
flowchart TB
accTitle: एक ही file stream से जुड़ने वाले तीन paths
accDescr: Cached ReadFile/WriteFile SharedCacheMap इस्तेमाल करते हैं, data-mapping fault DataSectionObject, और EXE/DLL image fault ImageSectionObject; तीनों SECTION_OBJECT_POINTERS से एक ही file stream से जुड़ते हैं
cached["Cached ReadFile / WriteFile"] --> scm["SharedCacheMap"]
dataFault["Data-mapping fault"] --> dso["DataSectionObject"]
imageFault["EXE/DLL image fault"] --> iso["ImageSectionObject"]
scm --> stream["एक ही file stream(SECTION_OBJECT_POINTERS)"]
dso --> stream
iso --> stream
चित्र 5: तीन paths अलग process होते हैं, लेकिन एक ही file stream से जुड़ते हैं।
तीनों में समान यह नहीं कि «सब Cache Manager में जाता है», बल्कि यह कि एक ही file stream cache, data section और image section जैसी अलग अवस्थाएँ SECTION_OBJECT_POINTERS से बाँधती है।5 Cache read-write, Lazy Writer, तथा Cc और Mm का संबंध «The Depths of Windows I/O (Part 4) — Cache Manager: When Does Your WriteFile Actually Reach the Disk?» में है।
ध्यान दें कि memory-mapped view को ReadFile/WriteFile से मिलाएँ तो हमेशा एक ही क्षण की content दिखने की गारंटी नहीं। डिज़ाइन में synchronization, flush और file-share mode होना चाहिए।36
8. Object और view का lifetime
केवल CreateFileMapping handle बंद करने से मौजूदा view नष्ट नहीं होता। View section का internal reference रखता है, और हर view के UnmapViewOfFile तथा हर handle के CloseHandle के बाद ही object नष्ट योग्य होता है।3
UnmapViewOfFile(view);
CloseHandle(mapping);
CloseHandle(file);
Lifetime का यह अलगाव «फ़ाइल बंद कर दी, फिर भी उपयोग में है» घटना का कारण है। File handle बंद करने के बाद भी अगर image section या data view file stream का reference रखे, फ़ाइल का अंतिम close बाद में आता है।
I/O पक्ष की cleanup/close से संबंध «The Depths of Windows I/O (Part 1)» में है, और implementation जाल «Shared Memory Pitfalls and Practical Best Practices» में।
9. स्वयं देखें
9.1. दो processes से एक ही DLL देखना
पहले मौजूदा processes से DLL sharing पुष्टि करें।
- Administrator के रूप में Process Explorer शुरू करें।
- दो
cmd.exeprocesses शुरू करें। - View > Lower Pane View > DLLs चुनें।
- दोनों processes में एक ही DLL का path और mapping पुष्टि करें।
- VMMap में प्रत्येक
cmd.exeखोलें और Images Working Set, Private तथा Shareable तुलना करें।
Process Explorer में एक ही DLL दिखना प्रमाण है कि दोनों ने एक ही image map की। अकेले इससे यह सिद्ध नहीं होता कि हर page का PFN मेल खाता है। Per-page sharing पुष्टि के लिए VMMap का Shareable विभाजन, RAMMap और QueryWorkingSetEx मिलाएँ। Process Explorer और VMMap Sysinternals देते हैं।1011
9.2. दो processes से FILE_MAP_COPY देखना
निम्न प्रोग्राम एक ही फ़ाइल को CoW view के रूप में map करता है और QueryWorkingSetEx का Shared bit दिखाता है। File-mapping object PAGE_READONLY से बनता है, लेकिन वह protection FILE_MAP_COPY view से compatible है, और view पक्ष की पहली लेखन 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);
}
बनाएँ और तैयार करें।
cl /std:c++20 /EHsc /W4 cow_demo.cpp
$path = "$env:TEMP\\cow-demo.bin"
[IO.File]::WriteAllBytes($path, [byte[]]::new(65536))
फिर दो consoles से एक ही फ़ाइल खोलें।
.\\cow_demo.exe "$env:TEMP\\cow-demo.bin" read
.\\cow_demo.exe "$env:TEMP\\cow-demo.bin" write
दोनों शुरू करने के बाद पहले read पक्ष फिर write पक्ष पर Enter दबाएँ, और पुष्टि करें कि दोनों के before में Shared set है। Write पक्ष पर फिर Enter दबाएँ तो उस process का page Shared 0 हो जाता है। फिर read पक्ष पर Enter दबाएँ और पुष्टि करें कि पाठक मूल page पढ़ता रहता है। लिखने के बाद भी VirtualQuery का Type MEM_MAPPED रहता है।
ध्यान दें कि PrintPage पूछने से ठीक पहले target page को फिर छूता है, और Valid == 0 हो तो Shared तथा ShareCount की व्याख्या नहीं करता और तीन बार तक retry करता है। अगर page अभी भी resident नहीं तो परिणाम नहीं देता और यह बताता है। ShareCount समय और memory pressure से बदल सकता है, इसलिए Valid == 1 पर पुष्ट Shared bit का बदलाव देखें, कोई स्थिर मान नहीं।
10. व्यवहार में बचने योग्य पाँच गलत पाठ
10.1. «Shared memory एक ही virtual address पर पहुँचती है»
Share section और physical page है। View का virtual address process के अनुसार भिन्न हो सकता है, इसलिए raw pointers के बजाय offsets रखें।
10.2. «अगर वही DLL है तो हर page आवश्यक रूप से share है»
Clean code pages share करना आसान है, जबकि relocation, writable sections, CoW और माप के क्षण की residency भी Private pages पैदा करते हैं।
10.3. «CoW के बाद यह MEM_PRIVATE हो जाता है»
VirtualQuery का Type MEM_MAPPED या MEM_IMAGE रहता है। वास्तविक sharing QueryWorkingSetEx से पुष्टि करें।7
10.4. «अगर Private Bytes नहीं बढ़े तो CoW नहीं हुआ»
FILE_MAP_COPY पूरे view का Commit पहले लगाता है। Private WS और Shared bit प्राथमिकता दें।6
10.5. «अगर page share है तो synchronization अनावश्यक है»
एक ही physical page देखना और कई CPU cores से सुरक्षित update करना अलग समस्याएँ हैं। Atomicity, memory order, mutual exclusion, crash के समय mid-state, और version compatibility डिज़ाइन करें।
Reference और lifetime को अलग-अलग अनुसरण करने का विचार Excel COM interop के बाद बचे processes की समस्या पर भी लागू होता है। देखें «Why EXCEL.EXE Processes Remain After C# Excel COM Automation — Reference Release Patterns and the Replacement Decision»।
11. सार
- Section object share करने योग्य memory range दर्शाता है, और हर process उसे अपने virtual space में view के रूप में map करता है।1
- एक ही section का एक ही offset अलग virtual addresses से एक ही physical page पर map होता है।2
- File-backed section वास्तविक फ़ाइल थामता है; pagefile-backed section named shared memory आदि थामता है।9
- EXE/DLL image section और साधारण फ़ाइल data section मानी जाती है; protection और वापस लिखने का गंतव्य भिन्न हैं।3
- CoW पठन के दौरान physical page share करता है और पहली लेखन पर केवल वही page कॉपी कर PTE बदलता है।4
- CoW के बाद भी
VirtualQueryMEM_MAPPED/MEM_IMAGEलौटाता है, इसलिएQueryWorkingSetExके Shared bit से पुष्टि करें।7 FILE_MAP_COPYमें पूरे view का Commit पहले लगता है, इसलिए अकेले Private Bytes से CoW नहीं आँका जा सकता।6- Cache Manager का cached I/O, data mapping और image mapping एक ही file stream से अलग paths के रूप में जुड़ते हैं जो क्रमशः
SharedCacheMap,DataSectionObjectऔरImageSectionObjectइस्तेमाल करते हैं।5 - Shared memory तभी सुरक्षित होती है जब view और handle का lifetime, synchronization, ACL और offset डिज़ाइन शामिल हों।
इससे «Windows मेमोरी की गहराई» के तीनों भाग पूरे होते हैं। आप virtual address Reserve/Commit करते हैं, page fault से physical page पाते हैं, page को Working Set से page list पर ले जाते हैं, section से share करते हैं, और केवल लिखे pages CoW से बाँटते हैं — Windows memory management इसी एक flow से जुड़ा है।
संबंधित लेख
- Windows मेमोरी की गहराई (भाग 1) — वह क्षण जब virtual address physical RAM बनता है: page fault शुरू से अंत तक
- Windows मेमोरी की गहराई (भाग 2) — एक physical page का जीवन: पाँच सूचियाँ और 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
संबंधित परामर्श क्षेत्र
KomuraSoft LLC Windows applications की shared memory, file mapping, DLL loading, file locking, inter-process communication और memory उपयोग की दोष जाँच संभालती है।
संदर्भ लिंक
-
Microsoft Learn, Section Objects and Views. Section object के share करने योग्य memory range दर्शाने, और हर process के section का भाग view के रूप में map करने पर। ↩ ↩2 ↩3
-
Microsoft Learn, File-Backed and Page-File-Backed Sections. File-backed और pagefile-backed sections, CoW, तथा अलग processes के virtual addresses से एक ही physical memory share करने पर। ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, CreateFileMappingW function. File-mapping object, pagefile-backed section,
SEC_IMAGE, view और handle का lifetime, तथा एक ही फ़ाइल थामने वाले views की consistency पर। ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, Memory Protection. कई processes के एक ही DLL के physical pages share करने, और एक पक्ष के लिखने पर CoW के नए physical page पर कॉपी कर PTE update करने पर। ↩ ↩2 ↩3
-
Microsoft Learn, SECTION_OBJECT_POINTERS structure. DataSectionObject, SharedCacheMap और ImageSectionObject के file stream mapping तथा cache जानकारी को memory manager / Cache Manager से बाँधने पर। ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, MapViewOfFileEx function.
FILE_MAP_COPYके साथ CoW; page file से backed private pages; पूरे view का Commit charge; तथा virtual address के बजाय offset रखने पर। ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, VirtualQuery function. CoW के बाद Type के
MEM_MAPPED/MEM_IMAGEरहने, तथाQueryWorkingSetExके Shared bit से privatization पुष्टि पर। ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Managing Memory Sections. View तक पहुँचने तक physical memory न दिए जाने, और पहली पहुँच के page fault के फ़ाइल content पढ़ने पर। ↩
-
Microsoft Learn, Sharing Files and Memory. नाम या handle से एक ही file-mapping object share करने;
INVALID_HANDLE_VALUEसे pagefile-backed shared memory बनाने; तथा synchronization अलग आवश्यक होने पर। ↩ ↩2 ↩3 -
Microsoft Learn, Process Explorer - Sysinternals. Process Explorer के process handles तथा loaded DLL / memory-mapped फ़ाइलें दिखाने पर। ↩
-
Microsoft Learn, VMMap - Sysinternals. VMMap के process virtual memory को Image, Mapped File, Private आदि में बाँटने, तथा Working Set का Private/Shareable विभाजन दिखाने पर। ↩
संबंधित लेख
निकटवर्ती विषयों में गहराई से जाने के लिए समान टैग वाले नवीनतम लेख।
DllMain और Loader Lock — DLL initialization में "कुछ मत करो" कहा जाने का असली कारण
DllMain से LoadLibrary क्यों न call करें और दूसरे thread से synchronize न करें। Primary sources से यह लेख बताता है कि loader lock हर DLL ...
Windows Virtualization Internals (भाग 3) — सेकंडों में boot होने वाली VMs: WSL2, Windows Sandbox और containers इतने हल्के क्यों हैं
WSL2 और Windows Sandbox सेकंडों में start होकर इतने हल्के क्यों लगते हैं? यह लेख dynamic base image और direct map से dynamic memory alloc...
Windows Virtualization Internals (भाग 2) — वो मेमोरी जिसे कर्नेल भी नहीं देख सकता: VBS, HVCI और Credential Guard कैसे काम करते हैं
Compatible hardware पर clean install में VBS default से enable होता है और hypervisor तथा SLAT से kernel से मज़बूत isolation बनाता है। यह ...
Windows virtualization की गहराई (भाग 1) — आपका Windows वास्तव में कहाँ चल रहा है? Hypervisor और partitions
जब आप Hyper-V enable करते हैं, तो host Windows खुद root partition के रूप में hypervisor के ऊपर चलता है। यह लेख VT-x, SLAT और VMBus की भूम...
Win32 Thread Pool API — CreateThreadpoolWork से thread बनाए बिना concurrency
क्या आपके native code में CreateThread calls बिखरी पड़ी हैं? यह लेख Vista में redesign की गई Win32 thread pool API — work, timer, wait और...
संबंधित विषय
ये पृष्ठ विषय को सेवाओं और निर्णयों के व्यापक संदर्भ में रखते हैं।
Windows के तकनीकी विषय
Windows विकास, बग जाँच और मौजूदा संपत्तियों के उपयोग का प्रवेश-द्वार।
इस विषय से जुड़ी सेवाएँ
यह लेख निम्नलिखित सेवाओं से सीधे जुड़ा है।
Windows ऐप विकास
व्यावसायिक ऐप, डिवाइस एकीकरण और संचार उपकरण, आवश्यकताओं से विकास तक।
अक्सर पूछे जाने वाले प्रश्न
इस लेख के विषय पर परामर्श में अक्सर पूछे जाने वाले प्रश्न।
- क्या एक ही DLL इस्तेमाल करने वाला हर process RAM में उस DLL की पूरी कॉपी पाता है?
- आमतौर पर नहीं। उसी image के unmodified pages हर process के अलग virtual addresses से एक ही physical page पर map होते हैं। केवल वे pages जिन्हें लिखना हो, copy-on-write आदि से process-private physical pages बनते हैं।
- क्या CreateFileMapping उसी क्षण process को memory allocate करता है?
- CreateFileMapping file-mapping object बनाता है, लेकिन उसे process के virtual space में दिखाने वाला MapViewOfFile है। इसके अलावा view के physical pages आमतौर पर पहली बार छुए गए page से page fault द्वारा साकार होते हैं।
- FILE_MAP_WRITE और FILE_MAP_COPY में क्या अंतर है?
- FILE_MAP_WRITE के ज़रिए बदलाव shared file-data पक्ष पर दिखने वाली लिखत है। FILE_MAP_COPY प्रारंभिक pages share करता है, लेकिन केवल लिखे गए pages process-private कॉपी बनते हैं; बदलाव मूल फ़ाइल में वापस नहीं लिखे जाते और view unmap होते ही खो जाते हैं।
- Copy-on-write के बाद क्या VirtualQuery MEM_PRIVATE लौटाता है?
- नहीं। Data view MEM_MAPPED और image view MEM_IMAGE रहता है। यह देखने के लिए कि page वास्तव में private हुआ या नहीं, page को resident बनाएँ और QueryWorkingSetEx का Shared bit देखें।
- क्या shared memory में raw pointer रखना चाहिए?
- आमतौर पर नहीं। एक ही section होने पर भी कोई गारंटी नहीं कि हर process का view एक ही virtual address पर होगा। Shared structure में base से offset, fixed-width integers, तथा स्पष्ट layout और synchronization योजना इस्तेमाल करें।