The Depths of Windows Memory (Part 1) — The Moment a Virtual Address Becomes Physical RAM: A Page Fault from Start to Finish

· · Windows, Memory Management, VirtualAlloc, Page Fault, VAD, Performance Monitoring

Passing MEM_COMMIT to VirtualAlloc increases Commit at that moment. Working Set, however, does not necessarily increase by the same amount. So where is the memory you thought you had allocated?

The answer is that most pages do not yet have corresponding physical RAM. Windows delays assigning a physical page until the application actually touches the page. When the first access causes the CPU to raise a page fault, the memory manager examines the VAD, the PTE, the protection attributes, and the backing store, and binds RAM one page at a time if needed.1

This article follows the path that “the first byte you touch” takes until it reaches physical RAM. If you want to sort out the meaning of figures such as Working Set and Commit first, see the introductory article “What Does Windows’ “Memory Usage” Actually Mean? — Correctly Reading Working Set, Private Bytes, Commit, and the Page File”. This series does not redefine the terms used there; it digs into “why the number comes out that way” from the mechanism side.

“The Depths of Windows Memory” — All 3 Parts

  1. Part 1 (this article): Virtual Addresses and Page Faults
    We follow when a region allocated with VirtualAlloc obtains physical RAM.
  2. Part 2: The Life of a Physical Page
    We follow how a page that leaves the Working Set moves through Modified, Standby, Free, and Zeroed.
  3. Part 3: Section Objects and Copy-on-Write
    We follow why DLLs, file mappings, and shared memory can share physical pages.

The question Part 1 answers is just one.

At what moment does a committed virtual address become physical RAM?

Intended readers are developers and operators who want to understand, from the mechanism up, Windows app memory usage, page faults right after startup, 0xC0000005, and the numbers in VMMap and PerfMon. Prerequisites are Windows 10/11 or current Windows Server, and required background is pointers and the basics of VirtualAlloc; you do not need experience with page-table bit layouts or a kernel debugger. The difficulty is intermediate. We use the names of internal structures, but we do not assume undocumented layouts that depend on a particular Windows build.

1. The Bottom Line First

The ordinary private-memory flow, in one line, is this.

Reserve sets aside a virtual address range, Commit charges a commit fee to guarantee a future place to keep the contents, and the page fault on first access assigns the physical page.

In other words, MEM_COMMIT is not an order that says “allocate RAM right now”. Microsoft’s VirtualAlloc documentation also guarantees that the initial contents of a committed page are zero, while explaining that the actual physical page is not assigned until the virtual address is accessed.1

That said, it is also inaccurate to claim that “Reserve/Commit only write to the VAD”. In practice, Reserve mainly creates a VAD that represents the virtual address range and its attributes, and Commit increases the system’s Commit Total and records the committed state of the range. Intermediate page-table levels and individual PTEs are built lazily when needed, and the final binding to physical RAM normally happens on first access.

Commit is not an empty promise; it is a system-wide promise that the contents can be kept in the future in RAM or an appropriate backing store. The entry point that materializes that promise one page at a time is the page fault.

What happens at Reserve, Commit, and first accessMEM_RESERVE records the range and attributes in the VAD, MEM_COMMIT consumes Commit Total to promise storage, and the page fault on first access assigns a physical page and adds it to the Working Set1. MEM_RESERVE2. MEM_COMMIT3. First access (Touch)Record the range and attributes in the VADConsume Commit Total (no physical page yet)Page faultBind a zeroed physical page to the PTEAdd it to the Working Set and re-execute the instruction

Figure 1: Reserve, Commit, and Touch are separate events. Physical RAM is bound only at the last step, the first access.

2. Three Ledgers That Track a Virtual Page

To understand the path from a virtual address to physical RAM, you need to distinguish the three kinds of ledger Windows keeps.

Ledger Unit Role
VAD Virtual address range Manages what the region is, Reserve/Commit, protection, and section correspondence
Page table / PTE Virtual page Represents the current translation to a physical page, or an unrealized state
PFN database Physical page Tracks ownership, references, and state of each RAM page

The VAD holds information about a range, the PTE about a virtual page, and the PFN database about a physical page. The page-fault handler cross-checks these to decide whether the access can continue.

Three ledgers from a virtual address to physical RAMA virtual address is managed by the VAD at range granularity and by the PTE at virtual-page granularity, and the PFN database tracks the physical page that is the PTE's translation target at physical-page granularityJudge Reserve/Commit and protectionValid translationVirtual addressVAD (range ledger)PTE (virtual-page ledger)PFN database (physical-page ledger)Physical RAM page

Figure 2: Three ledgers at different granularities. Fault handling cross-checks the VAD and the PTE, then reflects the result on the PFN side.

The stars of this article are the VAD and the PTE. We will look at the PFN database from the physical-page side in Part 2.

3. Reserve, Commit, and Touch Are Separate Events

3.1. Reserve — Claiming an Address

First, reserve a contiguous 256MiB virtual address range.

void* base = VirtualAlloc(
    nullptr,
    256ull * 1024 * 1024,
    MEM_RESERVE,
    PAGE_NOACCESS);

What happened at this point is only that an address was set aside in the process’s virtual space so that other allocations cannot use this range. MEM_RESERVE assigns no physical storage in RAM or in the page file.1

Because a 64-bit process has a vast virtual space, it becomes practical to Reserve a large range first and Commit only the parts you need later.

3.2. Commit — Promising That It Can Be Kept

Next, Commit the reserved range.

void* committed = VirtualAlloc(
    base,
    256ull * 1024 * 1024,
    MEM_COMMIT,
    PAGE_READWRITE);

On success, the promised amount that is reflected in the system’s Commit Total — and usually in the process’s Private Bytes — increases. Even so, 256MiB of physical pages do not line up all at once. Ordinary pages remain physically unassigned until first access.12

So what is the point of Commit? It is that when the system cannot take on the promise, it can return failure at Commit time, rather than in the middle of using the memory.

3.3. Touch — When a Physical Page Becomes Necessary

Finally, the following assignment writes to the first page for the first time.

static_cast<unsigned char*>(base)[0] = 1;

The CPU tries to translate the virtual address to a physical address, but the PTE does not yet have a valid translation to a physical page. A page fault occurs here.

The memory manager that receives control judges this to be “a first access to a committed, writable private page”, obtains a zeroed physical page, binds it to the PTE, and adds it to the Working Set. It then re-executes the write instruction that failed.

From the app it looks like a mere assignment, but internally control enters the kernel in the middle of the assignment, a physical page is assigned, and execution returns to the same instruction.

4. The VAD — the Range Ledger for Virtual Space

VAD stands for Virtual Address Descriptor, and Windows manages a process’s in-use address ranges as a tree of VADs. With WinDbg’s !vad command you can inspect the start and end VPNs, Commit, protection attributes, Private/Mapped, the Control Area, and more.3

Representative information a VAD records includes the following.

  • Start and end of the address range
  • Kind, such as Private, Mapped, or Image
  • Reserve/Commit state
  • Protection such as read, write, execute, and Copy-on-Write
  • Correspondence to a file or section
  • Special attributes such as guard pages

The reason for managing by range is efficiency. 256MiB is 65,536 pages at 4KiB. Rather than building a complete management structure for every page up front, it is less wasteful to hold “this contiguous range is one reservation” in a VAD and materialize pages as they become necessary.

4.1. Finding a VAD Does Not Guarantee Recovery

“If it is in a VAD the fault is resolved; if it is not, you get an access violation” is a convenient entry-level explanation, but it oversimplifies. Even when a VAD is found, ordinary access cannot continue in cases such as the following.

  • Reserve only, and the target page is not committed
  • PAGE_NOACCESS
  • A write to a read-only page
  • Instruction execution from a non-executable page
  • First touch of a guard page
  • A touch outside the valid range of a section

Conversely, even if the PTE is invalid, if the software state of the VAD and PTE shows a legitimate access, it can be resolved as demand-zero, a Transition restore, a page-in, or CoW. More precisely, the answer is judge VAD, PTE, protection attributes, and access type together.

5. Page Tables and the TLB

The pointer an app holds is a virtual address. For the CPU to access RAM, it must translate a virtual page number into a physical page number. That hierarchical translation table is the page table, and the leaf entry is the PTE (Page Table Entry).

A valid PTE conceptually holds a PFN, read/write/execute protection, user-mode permission, Accessed/Dirty, and similar information. The actual bit layout depends on the CPU and the Windows version.

Walking the page table every time would be far too slow, so the CPU caches recent translations in the TLB (Translation Lookaside Buffer). Address translation proceeds in this order.

  1. If the TLB has a translation and the access matches that protection, that result is used.
  2. If the TLB has no translation, the CPU walks the page table.
  3. If there is a valid PTE and the protection also matches, it is registered in the TLB and execution continues.
  4. If there is no valid translation, or there is a protection violation, control proceeds to the page-fault entry point. The protection check is also performed when the translation came from the TLB.

As this flow shows, a TLB miss and a page fault are different things. If the only issue is that the TLB has no translation and the PTE is valid, a page-table walk is all that happens. Conversely, even if the TLB has a translation, a protection violation such as a write to a read-only page or instruction execution on a non-executable page proceeds to the page-fault entry point. That is why a write to a CoW page can fault even when the translation is already cached.

Address-translation flow and the page-fault entry pointEven if the TLB has a translation, a protection mismatch proceeds to the page-fault entry point. If the TLB has no translation the page table is walked; a valid PTE that also matches protection is registered in the TLB and execution continues, and an invalid translation or protection violation proceeds to the page-fault entry pointYesMatchProtection violationNoYesInvalid or protection violationMemory accessDoes the TLB have a translation?Does the access match the protection?Continue with that translationTo the page-fault entry pointPage-table walkValid PTE and protection also matches?Register in the TLB and continue (no fault)

Figure 3: A TLB miss can be resolved by a page-table walk. Control proceeds to a page fault when the translation is invalid or there is a protection violation, and a protection violation occurs even on a TLB hit.

5.1. An Invalid PTE Is Not Merely a Blank

Even an invalid PTE is not empty. From the software state of an invalid PTE, Windows distinguishes cases such as the following.

  • A demand-zero page that has never been materialized
  • A Transition page that remains in RAM
  • A shared page that refers to a Prototype PTE
  • A private page saved in the page file
  • A protection violation or an invalid region

The CPU’s job is only to decide “this is not an ordinary valid translation” and hand it to the kernel; the memory manager supplies the meaning from there.

6. A Page Fault from Start to Finish

Let us follow a first write to a committed private page in six stages.

  1. The CPU tries to write.
    It checks the TLB and the page table, but the target PTE has no valid PFN.
  2. The CPU raises a page fault.
    It passes the faulting virtual address, the read/write/execute type, user/kernel, and whether the issue is a missing translation or a protection violation to the kernel.
  3. The memory manager examines the VAD and the PTE.
    It decides whether the page is committed, whether the protection matches, and which of demand-zero, Transition, shared, page-in, CoW, or an exception applies.
  4. If it is demand-zero, a zeroed physical page is obtained.
    A newly handed-out page must be zero so that another process’s data is not leaked.
  5. The PTE and PFN management information are updated.
    The PFN and protection are set in the PTE, the physical page is made Active, and it is added to the process’s Working Set.
  6. The failed instruction is re-executed.
    Because the fault resolved normally, no user-mode exception is delivered, and the app continues the assignment as usual.

ETW page-fault events also record Transition, Demand Zero, Copy-on-Write, Guard Page, Hard Page Fault, and Access Violation as distinct kinds.4

So a page fault is not a word that means “abnormal” from the start. It is the common entry point for asking the OS to decide when the CPU could not translate on the ordinary path.

Branching of page-fault resolutionsThe memory manager judges the VAD, PTE, protection attributes, and access type, and dispatches to demand-zero, reconnecting a page still in RAM, a hard fault from a backing store, copy-on-write, a guard-page notification, or an exceptionFirst accessStill in RAMDisk read requiredCoW writeGuard pageUnresolvablePage fault occursJudge VAD, PTE, protection, typeDemand-zero (soft)Reconnect from Standby (soft)Hard fault (disk I/O)Copy and swap the PTEClear guard and notifyException (0xC0000005 etc.)

Figure 4: Faults that enter through the same entry point split into six kinds of outcome depending on the judgment. Guard-page details are covered in section 9.

7. Demand-Zero — a Soft Fault That Does Not Read Disk

Demand-zero is the representative soft fault that occurs when a committed private page is first touched. Microsoft’s Working Set documentation also lists “the process refers to an allocated virtual page for the first time” as an example of a soft fault.5

Demand-zero has the following characteristics.

  • There is no need to read original data from disk
  • The initial contents are zero
  • An available physical page is bound
  • Working Set and the cumulative Page Fault Count increase
  • This handling alone does not increase Memory\\Pages Input/sec

That is why a spike in Page Faults/sec right after startup does not by itself mean that storage is the bottleneck.

The trade-off of lazy allocation is worth sorting out as well. If you Commit 256MiB and actually use only 8MiB, leaving the remaining 248MiB out of RAM is reasonable. In exchange, first access carries the cost of fault handling. For latency-sensitive work there is a design that touches each page before starting in order to prefault, but that is a trade-off that increases RAM residency up front.

8. Soft Faults and Hard Faults

8.1. Soft Faults

A soft fault is a fault that can be resolved with no read I/O to a backing store. Representative examples include the following.

  • Demand-zero
  • Reconnecting a page that remains on Standby/Transition
  • Connecting a shared page that is in another process’s Working Set
  • Connecting a prefetched page
  • Copy-on-Write whose original page is resident

There is still CPU cost for the kernel transition, locks, PTE/PFN updates, TLB coherence, and the like, but there is no storage wait.5

8.2. Hard Faults

On the other hand, when the needed page is nowhere in RAM and must be read from a backing store, that is a hard fault. The read source is not only the page file.

  • A private page that was written out to the page file
  • A memory-mapped file
  • An EXE or DLL image
  • A data file referenced by the file cache

ETW HardFault events include FileObject, ReadOffset, and ByteCount, so you can track the actual read source.6

Therefore Hard Fault = a read of pagefile.sys is not true.

When a backing-store read is required, the request enters the Windows I/O stack. The flow of IRPs and issue/completion is covered in “The Depths of Windows I/O (Part 1)”, and the junction with the file cache is covered in “The Depths of Windows I/O (Part 4)”. If the page is in RAM the memory manager can return on its own; if it is not, it issues I/O and waits the faulting thread until completion.

9. An Unresolvable Fault Becomes an Exception

A fault that, after examining the VAD and PTE, cannot be resolved as a legitimate allocation, page-in, or CoW is delivered to user mode as an exception.

The representative case is STATUS_ACCESS_VIOLATION, exception code 0xC0000005. It occurs on a read, write, or execute of an invalid address; the first exception parameter indicates the access type and the second the violating address.7

Typical patterns include the following.

  • Reading NULL, a freed address, or an address outside an array
  • Writing to a read-only page
  • Executing an instruction from a page that DEP/NX has made non-executable
  • Touching a reserved range that is not committed

PAGE_GUARD has a slightly different meaning. It is a one-shot notification of access: it raises STATUS_GUARD_PAGE_VIOLATION and is used for things such as stack growth.8

Normal lazy allocation, page-in, CoW, guard notification, and a final access violation all gather, from the CPU’s point of view, at the same page-fault entry point. What decides the outcome is the combination of VAD, PTE, protection attributes, and access type.

10. See It for Yourself

You can observe the flow so far on your own machine. The following C++ program Reserves 256MiB, Commits it, writes one byte to each page, and finally Releases. It waits for Enter at each stage so you can observe the changes in VMMap and PerfMon.

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

#include <cstdio>
#include <cstdlib>

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

constexpr SIZE_T kSize = 256ull * 1024 * 1024;

void PrintMemory(const char* stage)
{
    PROCESS_MEMORY_COUNTERS_EX c{};
    c.cb = sizeof(c);
    if (!GetProcessMemoryInfo(
            GetCurrentProcess(),
            reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&c),
            sizeof(c))) {
        std::printf("GetProcessMemoryInfo failed: %lu\n", GetLastError());
        return;
    }

    std::printf(
        "%-10s WS=%zu MiB  Private=%zu MiB  Faults=%lu\n",
        stage,
        c.WorkingSetSize / 1024 / 1024,
        c.PrivateUsage / 1024 / 1024,
        c.PageFaultCount);
}

void Pause(const char* message)
{
    PrintMemory(message);
    std::puts("Press Enter...");
    (void)std::getchar();
}

int main()
{
    SYSTEM_INFO si{};
    GetSystemInfo(&si);
    std::printf("PID=%lu, page=%lu bytes\n",
                GetCurrentProcessId(), si.dwPageSize);

    void* base = VirtualAlloc(nullptr, kSize, MEM_RESERVE, PAGE_NOACCESS);
    if (!base) {
        std::fprintf(stderr, "Reserve failed: %lu\n", GetLastError());
        return EXIT_FAILURE;
    }
    Pause("reserved");

    if (!VirtualAlloc(base, kSize, MEM_COMMIT, PAGE_READWRITE)) {
        std::fprintf(stderr, "Commit failed: %lu\n", GetLastError());
        VirtualFree(base, 0, MEM_RELEASE);
        return EXIT_FAILURE;
    }
    Pause("committed");

    auto* bytes = static_cast<volatile unsigned char*>(base);
    for (SIZE_T offset = 0; offset < kSize; offset += si.dwPageSize) {
        bytes[offset] = 1;
    }
    Pause("touched");

    if (!VirtualFree(base, 0, MEM_RELEASE)) {
        std::fprintf(stderr, "Release failed: %lu\n", GetLastError());
        return EXIT_FAILURE;
    }
    Pause("released");
}

From Visual Studio’s x64 Native Tools Command Prompt, you can build with the following command.

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

10.1. What to Look at in VMMap

VMMap is a tool that displays reserved virtual memory, Commit, Working Set, Private, and Shareable by type.9 The changes to expect at each stage are as follows.

Stage Expected change
Reserve Address Space Size increases, but Commit/WS do not increase by the same amount
Commit Private Commit increases by about 256MiB
Touch Working Set and Private WS increase substantially, and the Fault Count also increases
Release The target range disappears, and Commit and WS drop

Actual numbers vary with the runtime, security products, memory pressure, and when you observe. Look at which way the numbers moved between stages, not at whether they come out to exactly 256MiB.

10.2. Separating Soft and Hard in PerfMon

In PerfMon, place the following counters on the same timeline.

  • Process(<target>)\\Page Faults/sec
  • Memory\\Pages Input/sec
  • Memory\\Page Reads/sec
  • Memory\\Available MBytes
  • Process(<target>)\\Working Set - Private
  • Process(<target>)\\Private Bytes

Process\\Page Faults/sec includes both soft and hard faults. Memory\\Pages Input/sec, on the other hand, is the number of pages read from disk to resolve hard faults.10

In this program’s Touch stage, Page Faults/sec should jump while Pages Input/sec should not rise much. Newly committed pages are materialized by demand-zero, so there is no need to read original data from disk.

When several processes share the same name, PerfMon numbers such as process#1 can change across restarts. Cross-check against a counter that displays the PID, or identify by PID with Process V2 or ETW/WPA.

11. Three Misreadings to Avoid in Practice

11.1. “Commit went up, so it is a RAM leak”

Commit is the promised amount of contents to keep; untouched pages may not be resident in RAM. To judge a leak, look at the time series of Private Bytes, the breakdown of allocations, and whether the figure returns to a baseline after processing ends.

11.2. “Page Faults/sec is high, so the disk is slow”

Soft faults involve no disk I/O. Separate Page Faults/sec, Pages Input/sec, and storage wait, and if needed follow the source file and stack with ETW HardFault events.

11.3. “Emptying the Working Set will fix the leak”

Removing a page from the Working Set does not release Commit or ownership. The page moves to Standby or Modified and later faults back in. Fixing a leak requires the allocator to perform VirtualFree, a heap free, object destruction, and the like.

Where that removed physical page goes is what we follow in Part 2.

12. Summary

  • MEM_RESERVE sets aside a virtual address range but assigns no physical region in RAM or the page file.1
  • MEM_COMMIT consumes Commit and guarantees that the contents can be kept in the future, but an ordinary physical page is not assigned until first access.12
  • The VAD is the range ledger, the PTE the virtual-page ledger, and the PFN database the physical-page ledger.
  • A TLB miss is not a page fault. If the PTE is valid, a page-table walk alone resolves it.
  • Demand-zero, Transition restore, and connecting a shared page are soft faults that can be resolved with no disk I/O.5
  • If a read from the page file, a DLL, an EXE, or a mapped file is required, it is a hard fault.6
  • If inspection of the VAD, PTE, and protection attributes cannot resolve the fault, you get an exception such as 0xC0000005.7
  • For a performance judgment, do not look at Page Faults/sec alone; look at Pages Input/sec, Available, Working Set, Private Bytes, and storage wait on the same timeline.

Continued in Part 2, “The Life of a Physical Page: Five Lists and the Truth About the Page File”.

After the Commit promise has been turned into a physical page, we follow where that page goes when it leaves the Working Set, from the PFN database and the page lists.

KomuraSoft LLC handles investigations of Windows application memory usage, access violations, startup delays, paging, and native-code defects.

References

  1. Microsoft Learn, VirtualAlloc function. On MEM_RESERVE reserving a virtual address range without assigning physical storage; MEM_COMMIT charging a commit fee against the system’s overall memory and page file; the initial contents of a committed page being zero; and the actual physical page not being assigned until it is accessed.  2 3 4 5 6

  2. Microsoft Learn, PERFORMANCE_INFORMATION structure. On CommitTotal being the current number of system Commit pages, and CommitLimit being the upper bound that can be committed without extending the page file.  2

  3. Microsoft Learn, !vad (WinDbg). On !vad displaying the VAD tree and letting you inspect start and end VPNs, Commit, Mapped/Private, protection attributes, the Control Area, and more. 

  4. Microsoft Learn, PageFault_TypeGroup1 class. On ETW distinguishing and recording Transition Fault, Demand Zero Fault, Copy-on-Write, Guard Page Fault, Hard Page Fault, and Access Violation. 

  5. Microsoft Learn, Working Set. On a soft fault being resolvable without accessing a backing store, and occurring from another process’s Working Set, Transition, first-reference demand-zero, and the like.  2 3

  6. Microsoft Learn, PageFault_HardFault class. On a HardFault event including FileObject, ReadOffset, ByteCount, VirtualAddress, and a Thread ID, so that the read source can be tracked.  2

  7. Microsoft Learn, Access Violation C0000005. On 0xC0000005 occurring on a read, write, or execute of an invalid memory address, and the exception parameters indicating the access type and the violating address.  2

  8. Microsoft Learn, Creating Guard Pages. On PAGE_GUARD providing a one-shot notification of page access and raising STATUS_GUARD_PAGE_VIOLATION

  9. Microsoft Learn, VMMap - Sysinternals. On VMMap breaking down committed virtual memory by type and displaying each type’s Working Set and a detailed address map. 

  10. Microsoft Learn, Performance Analysis of Logs (PAL) Tool. On Memory\\Pages Input/sec being the number of pages read from disk to resolve hard page faults. 

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 passing MEM_COMMIT to VirtualAlloc allocate RAM at that moment?
In ordinary private memory, Commit consumes the system's commit headroom, but the corresponding physical page is not assigned until the first access. A page first touched by a write obtains its physical page during demand-zero fault handling.
Does a page fault mean something is wrong or that you have a performance problem?
No. Soft faults that involve no disk I/O — such as demand-zero or returning a page from Standby — are normal operation. For a performance judgment, look not only at Page Faults/sec but also at Pages Input/sec, storage wait, and Available MBytes.
Are a TLB miss and a page fault the same thing?
They are different. Even if the TLB has no translation, if the page table's PTE is valid the CPU simply walks the table and re-registers the translation. It proceeds to the page-fault entry point when the PTE is invalid or there is a protection violation.
If the address range is in a VAD, you cannot get an access violation?
Not necessarily. In addition to whether a VAD exists, the memory manager evaluates Reserve versus Commit, read/write/execute protection, guard pages, the PTE state, and more. If the fault cannot be resolved, you get an exception such as 0xC0000005.
Does a high Page Faults/sec mean the system is short on RAM?
You cannot tell from that alone. Page Faults/sec also includes a large number of soft faults. You need to correlate it on the same timeline with Memory\Pages Input/sec, Memory\Page Reads/sec, Available MBytes, and disk wait time.

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