Die Tiefen des Windows-Speichers (Teil 1) — Der Moment, in dem eine virtuelle Adresse zu physischem RAM wird: ein Page Fault von Anfang bis Ende

· Aktualisiert am: · · Windows, Speicherverwaltung, VirtualAlloc, Page Fault, VAD, Leistungsüberwachung

Änderungsverlauf (Erstfassung, veröffentlicht am 20. Aug 2026)
Erstveröffentlichung
Diesen Artikel zitieren(DOI (registriertes Archiv): 10.5281/zenodo.22176068)

Die folgenden DOIs verweisen auf bereits archivierte Versionen, die vom aktuellen Text abweichen können. Verwenden Sie die URL dieser Seite, um auf den aktuellen Text zu verweisen.

Go Komura (2026). Die Tiefen des Windows-Speichers (Teil 1) — Der Moment, in dem eine virtuelle Adresse zu physischem RAM wird: ein Page Fault von Anfang bis Ende. KomuraSoft LLC. https://comcomponent.com/de/blog/windows-memory-internals-page-fault/

DOI (registriertes Archiv)
10.5281/zenodo.22176068
DOI (zuletzt registrierte Version)
10.5281/zenodo.22176069

„Ich habe 256MiB committet, aber das Working Set ist nicht um denselben Betrag gestiegen.“ Diese Frage beim Einsatz von VirtualAlloc ist der Ausgangspunkt von Teil 1.

Im gewöhnlichen privaten Speicher sind Commit und das Ablegen dieser Seite in physischem RAM getrennte Dinge. Windows verzögert die Zuweisung einer physischen Seite, bis die Anwendung die Seite tatsächlich berührt. Wenn der erste Zugriff einen Page Fault auslöst, prüft der Speicher-Manager VAD, PTE, Schutzattribute und den Backing Store und bindet bei Bedarf RAM Seite für Seite.1

Dieser Artikel folgt dem Weg, den „das erste Byte, das Sie berühren“ nimmt, bis es physisches RAM erreicht. Wenn Sie zuerst die Bedeutung der Zahlen Working Set und Commit klären wollen, siehe den Einführungsartikel „Was bedeutet Windows’ „Speicherauslastung“ eigentlich? — Working Set, Private Bytes, Commit und die Auslagerungsdatei richtig lesen“. Diese Reihe definiert die Begriffe nicht neu; sie gräbt von der Mechanik her, warum die Zahl so herauskommt.

„Die Tiefen des Windows-Speichers“ — alle 3 Teile

Die Reihe folgt der Reihenfolge eine physische Seite erhalten → Residenz und Rückgewinnung verfolgen → Teilen und Privatisieren verstehen.

Teil Thema Was dieser Teil verfolgt
Teil 1 (dieser Artikel) Virtuelle Adressen und Page Faults Wann ein mit VirtualAlloc zugewiesener Bereich physisches RAM erhält
Teil 2 Das Leben einer physischen Seite Die Zustandsübergänge einer Seite, die das Working Set verlässt, und die Rolle der Auslagerungsdatei
Teil 3 Section-Objekte und Copy-on-Write Wie DLLs, Dateizuordnungen und gemeinsamer Speicher physische Seiten teilen

Die Frage, die Teil 1 beantwortet, ist nur eine.

In welchem Moment wird eine committete virtuelle Adresse zu physischem RAM?

Bevor Sie beginnen Inhalt
Zielgruppe Entwickler und Betrieb, die Speicherverbrauch, Page Faults direkt nach dem Start, 0xC0000005 und die Zahlen in VMMap und PerfMon vom Mechanismus her verstehen wollen
Umgebung Windows 10/11 oder aktuelles Windows Server
Vorwissen Zeiger und die Grundlagen von VirtualAlloc
Schwierigkeit Mittelstufe. Erfahrung mit Bit-Layouts von Seitentabellen oder einem Kernel-Debugger ist nicht nötig

Wir verwenden die Namen interner Strukturen, setzen aber keine undokumentierten Layouts voraus, die von einem bestimmten Windows-Build abhängen.

In der Abbildung kennzeichnet eine durchgezogene Linie eine stets geltende Beziehung und eine gestrichelte Linie eine bedingte (die Bedingungen stehen bei jeder Beziehung auf der Detailseite). Die vollständige Liste der Beziehungen (14 insgesamt, mit Beleg und Sicherheitsgrad) und die Definitionen der wichtigsten Konzepte sind auf der Detailseite der Wissenskarte (auf Japanisch) zusammengestellt. Daten: JSON-LD / Turtle

1. Zuerst das Fazit

Im gewöhnlichen privaten Speicher macht die Trennung der folgenden drei Stufen den Unterschied zwischen Commit und Working Set sichtbar.

  1. Reserve ist die Stufe, die eine Adresse im virtuellen Raum beansprucht. Der Bereich wird reserviert, aber in RAM oder Auslagerungsdatei wird kein physischer Speicher zugewiesen.1
  2. Commit ist die Stufe, in der das System verspricht, den Inhalt künftig halten zu können. Es erhebt eine Commit-Gebühr und erhöht das Commit Total, bindet aber normalerweise noch nicht jeder Seite physisches RAM.12
  3. Touch ist die Stufe, in der eine physische Seite tatsächlich nötig wird. Der erste Zugriff löst einen Page Fault aus, und bei einem zulässigen Zugriff weist der Speicher-Manager eine physische Seite zu und führt den Befehl erneut aus.

MEM_COMMIT ist kein Befehl „weise jetzt sofort RAM zu“. Es ist auch kein leeres Versprechen, sondern ein systemweites Versprechen, dass der Inhalt künftig in RAM oder einem geeigneten Backing Store gehalten werden kann. Dass der Anfangsinhalt einer committeten Seite null ist und dass bis zum ersten Zugriff keine physische Seite zugewiesen wird, schließt sich nicht aus.1

Auch die Vorstellung „Reserve/Commit schreiben nur in den VAD“ ist ungenau. Reserve erzeugt vor allem einen VAD, der Bereich und Attribute darstellt, und Commit erhöht das Commit Total des Systems und zeichnet den committeten Zustand des Bereichs auf. Zwischenstufen der Seitentabelle und einzelne PTEs werden verzögert gebaut, sobald sie nötig werden.

Was Sie wissen wollen Zu lesende Abschnitte
Was sich bei Reserve, Commit und Touch ändert Abschnitte 2 bis 3
Was VAD, PTE und TLB entscheiden Abschnitte 4 bis 6
Normale Faults von E/A-Wartezeiten und Ausnahmen trennen Abschnitte 7 bis 9
An Zahlen auf dem eigenen Rechner prüfen Abschnitte 10 bis 11
Was bei Reserve, Commit und dem ersten Zugriff geschiehtMEM_RESERVE zeichnet Bereich und Attribute im VAD auf, MEM_COMMIT verbraucht Commit Total und verspricht Speicherung, und der Page Fault beim ersten Zugriff weist eine physische Seite zu und nimmt sie ins Working Set auf1. MEM_RESERVE2. MEM_COMMIT3. Erster Zugriff (Touch)Bereich und Attribute im VAD aufzeichnenCommit Total verbrauchen (noch keine physische Seite)Page FaultGenullte physische Seite an die PTE bindenIns Working Set aufnehmen und den Befehl erneut ausführen

Abbildung 1: Reserve, Commit und Touch sind getrennte Ereignisse. Physisches RAM wird erst beim letzten Schritt, dem ersten Zugriff, gebunden.

2. Drei Verzeichnisse, die einer virtuellen Seite folgen

Die Verzeichnisse von Windows betrachten denselben Speicher in unterschiedlichen Einheiten. Zuerst trennen Sie die drei: Bereich, virtuelle Seite und physische Seite.

Verzeichnis Einheit Rolle
VAD Virtueller Adressbereich Verwaltet, um welche Region es sich handelt, Reserve/Commit, Schutz und die Zuordnung zu einer Section
Seitentabelle / PTE Virtuelle Seite Stellt die aktuelle Übersetzung zu einer physischen Seite oder einen noch nicht materialisierten Zustand dar
PFN-Datenbank Physische Seite Verfolgt Besitz, Referenzen und Zustand jeder RAM-Seite

Der VAD hält Informationen über einen Bereich, die PTE über eine virtuelle Seite, die PFN-Datenbank über eine physische Seite. Der Page-Fault-Handler gleicht sie ab und entscheidet, ob der Zugriff fortgesetzt werden kann.

Drei Verzeichnisse von der virtuellen Adresse zum physischen RAMEine virtuelle Adresse wird vom VAD in Bereichsgranularität und von der PTE in Granularität der virtuellen Seite verwaltet, und die PFN-Datenbank verfolgt die physische Seite, in die die PTE übersetzt, in Granularität der physischen SeiteEntscheidet Reserve/Commit und SchutzGültige ÜbersetzungVirtuelle AdresseVAD (Verzeichnis der Bereiche)PTE (Verzeichnis der virtuellen Seiten)PFN-Datenbank (Verzeichnis der physischen Seiten)Physische RAM-Seite

Abbildung 2: Drei Verzeichnisse unterschiedlicher Granularität. Die Fault-Behandlung gleicht VAD und PTE ab und schreibt das Ergebnis auf der PFN-Seite fort.

Dieser Artikel stellt VAD und PTE in den Mittelpunkt. Die PFN-Datenbank betrachten wir in Teil 2 von der Seite der physischen Seite.

3. Reserve, Commit und Touch sind getrennte Ereignisse

3.1. Reserve — eine Adresse beanspruchen

Zuerst reservieren wir einen zusammenhängenden virtuellen Adressbereich von 256MiB.

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

Was in diesem Moment geschieht, ist nur, dass im virtuellen Raum des Prozesses eine Adresse beansprucht wird, damit andere Zuweisungen diesen Bereich nicht nutzen. MEM_RESERVE weist weder in RAM noch in der Auslagerungsdatei physischen Speicher zu.1

Weil ein 64-Bit-Prozess über einen weiten virtuellen Raum verfügt, wird ein Entwurf praktisch, der zuerst einen großen Bereich reserviert und später nur die benötigten Teile committet.

3.2. Commit — versprechen, dass der Inhalt gehalten werden kann

Als Nächstes committen wir den reservierten Bereich.

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

Bei Erfolg steigt die versprochene Menge, die sich im Commit Total des Systems und gewöhnlich in den Private Bytes des Prozesses niederschlägt. Trotzdem stehen nicht auf einmal 256MiB physische Seiten. Gewöhnliche Seiten bleiben bis zum ersten Zugriff physisch unzugewiesen.12

Wozu dient Commit dann? Dazu, dass das System, wenn es das Versprechen nicht übernehmen kann, bereits beim Commit fehlschlagen kann und nicht erst mitten in der Nutzung des Speichers.

3.3. Touch — wenn eine physische Seite nötig wird

Zuletzt schreibt die folgende Zuweisung zum ersten Mal auf die erste Seite.

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

Die CPU versucht, die virtuelle Adresse in eine physische Adresse zu übersetzen, aber die PTE hält noch keine gültige Übersetzung zu einer physischen Seite. Hier entsteht der Page Fault.

Der Speicher-Manager, der die Kontrolle übernimmt, erkennt „einen ersten Zugriff auf eine committete, schreibbare private Seite“, holt eine genullte physische Seite, bindet sie an die PTE und nimmt sie ins Working Set auf. Anschließend lässt er den fehlgeschlagenen Schreibbefehl erneut ausführen.

Aus Sicht der App ist es nur eine Zuweisung, intern aber tritt die Kontrolle mitten in der Zuweisung in den Kernel ein, eine physische Seite wird zugewiesen, und die Ausführung kehrt zu demselben Befehl zurück.

4. Der VAD — das Bereichsverzeichnis des virtuellen Raums

VAD steht für Virtual Address Descriptor, und Windows verwaltet die genutzten Adressbereiche eines Prozesses als Baum von VADs. Mit dem WinDbg-Befehl !vad können Sie Start- und End-VPN, Commit, Schutzattribute, Private/Mapped, Control Area und mehr prüfen.3

Typische Informationen, die ein VAD trägt, sind die folgenden.

  • Anfang und Ende des Adressbereichs
  • Die Art, etwa Private, Mapped oder Image
  • Der Reserve/Commit-Zustand
  • Schutz wie Lesen, Schreiben, Ausführen und Copy-on-Write
  • Die Zuordnung zu einer Datei oder Section
  • Besondere Attribute wie Guard-Seiten

Der Grund für die Verwaltung je Bereich ist, den Verwaltungsaufwand zu senken. 256MiB entsprechen 65.536 Seiten zu 4KiB.

Statt von Anfang an für jede Seite eine vollständige Verwaltungsstruktur zu bauen, verwaltet der VAD „dieser zusammenhängende Bereich ist eine Reservierung“. Darauf aufbauend werden Seiten materialisiert, sobald sie nötig werden.

4.1. Ein gefundenes VAD bedeutet nicht, dass der Fault immer auflösbar ist

Die Erklärung „steht es im VAD, wird der Fault aufgelöst, sonst Zugriffsverletzung“ ist als Einstieg nützlich, vereinfacht aber zu stark. Auch wenn ein VAD gefunden wird, kann ein gewöhnlicher Zugriff in Fällen wie den folgenden nicht fortgesetzt werden.

  • Es wurde nur Reserve ausgeführt, und die Zielseite ist nicht committet
  • Die Seite ist PAGE_NOACCESS
  • Es wurde auf eine schreibgeschützte Seite geschrieben
  • Ein Befehl wurde von einer nicht ausführbaren Seite ausgeführt
  • Eine Guard-Seite wurde zum ersten Mal berührt
  • Der Zugriff lag außerhalb des gültigen Bereichs einer Section

Umgekehrt kann selbst bei ungültiger PTE, wenn der Softwarezustand von VAD und PTE einen zulässigen Zugriff zeigt, als Demand-Zero, Transition-Wiederherstellung, Page-in oder CoW aufgelöst werden. Genau gesagt lautet die Antwort: VAD, PTE, Schutzattribute und Zugriffsart werden zusammen bewertet.

5. Seitentabelle und TLB

Der Zeiger einer App ist eine virtuelle Adresse. Damit die CPU auf RAM zugreifen kann, muss sie die virtuelle Seitennummer in eine physische Seitennummer übersetzen. Diese hierarchische Übersetzungstabelle ist die Seitentabelle, und der Blatt-Eintrag ist die PTE (Page Table Entry).

Eine gültige PTE hält begrifflich die PFN, Lese-/Schreib-/Ausführungsschutz, ob Benutzermodus zugreifen darf, Accessed/Dirty und Ähnliches. Das tatsächliche Bit-Layout hängt von CPU und Windows-Version ab.

Jedes Mal die Seitentabelle abzulaufen wäre jedoch zu langsam, deshalb speichert die CPU jüngste Übersetzungsergebnisse im TLB (Translation Lookaside Buffer). Die Adressübersetzung läuft in dieser Reihenfolge.

  1. Hat der TLB eine Übersetzung und entspricht der Zugriff ihrem Schutz, wird dieses Ergebnis verwendet.
  2. Hat der TLB keine Übersetzung, läuft die CPU die Seitentabelle ab.
  3. Gibt es eine gültige PTE und entspricht der Zugriff auch dem Schutz, wird die Übersetzung im TLB eingetragen und die Ausführung fortgesetzt.
  4. Gibt es keine gültige Übersetzung oder liegt ein Schutzverstoß vor, geht es zum Einstiegspunkt des Page Fault. Die Schutzprüfung erfolgt auch dann, wenn die Übersetzung aus dem TLB kam.

Leicht zu verwechseln ist hier, dass ein TLB-Miss und ein Page Fault verschiedene Dinge sind.

Lage Was als Nächstes geschieht
Der TLB hat eine Übersetzung, und der Zugriff entspricht dem Schutz Mit der gecachten Übersetzung fortfahren
Der TLB hat keine Übersetzung, aber es gibt eine gültige PTE, und der Zugriff entspricht dem Schutz Die Übersetzung per Page-Table-Walk holen und fortfahren
Es gibt keine gültige Übersetzung, oder der Zugriff verstößt gegen den Schutz Zum Einstiegspunkt des Page Fault gehen

Die Schutzprüfung wirkt auch bei einem TLB-Treffer. Ein Schreiben auf eine schreibgeschützte Seite oder das Ausführen eines Befehls auf einer nicht ausführbaren Seite löst auch bei bereits gecachter Übersetzung einen Fault aus. Deshalb kann auch ein Schreiben auf eine CoW-Seite einen Fault auslösen.

Ablauf der Adressübersetzung und Einstieg des Page FaultAuch wenn der TLB eine Übersetzung hat, geht ein Zugriff, der dem Schutz nicht entspricht, zum Einstieg des Page Fault. Fehlt die Übersetzung im TLB, wird die Seitentabelle abgelaufen; eine gültige PTE, deren Schutz ebenfalls passt, wird im TLB eingetragen und die Ausführung fortgesetzt, ungültig oder Schutzverstoß gehen zum Einstieg des Page FaultjaentsprichtSchutzverstoßneinjaungültig oder SchutzverstoßSpeicherzugriffHat der TLB eine Übersetzung?Entspricht der Zugriff dem Schutz?Mit dieser Übersetzung fortfahrenZum Einstieg des Page FaultPage-Table-WalkGültige PTE und Schutz entspricht ebenfalls?Im TLB eintragen und fortfahren (kein Fault)

Abbildung 3: Ein TLB-Miss lässt sich per Page-Table-Walk auflösen. Zum Page Fault geht es, wenn die Übersetzung ungültig ist oder ein Schutzverstoß vorliegt, und ein Schutzverstoß kann auch bei einem TLB-Treffer entstehen.

5.1. Eine ungültige PTE ist nicht bloß leer

Ungültige PTE heißt nicht, dass der Inhalt leer ist. Am Softwarezustand einer ungültigen PTE unterscheidet Windows Fälle wie die folgenden.

  • Eine Demand-Zero-Seite, die noch nie materialisiert wurde
  • Eine Transition-Seite, die im RAM bleibt
  • Eine gemeinsam genutzte Seite, die auf eine Prototype-PTE verweist
  • Eine private Seite, die in der Auslagerungsdatei gespeichert ist
  • Ein Schutzverstoß oder ein ungültiger Bereich

Die Aufgabe der CPU endet damit, „das ist keine gewöhnliche gültige Übersetzung“ zu entscheiden und an den Kernel zu übergeben; die Bedeutung danach setzt der Speicher-Manager.

6. Ein Page Fault von Anfang bis Ende

Verfolgen wir ein erstes Schreiben auf eine committete private Seite in sechs Stufen.

  1. Die CPU versucht zu schreiben.
    Sie prüft TLB und Seitentabelle, aber die Ziel-PTE hat keine gültige PFN.
  2. Die CPU löst einen Page Fault aus.
    Sie übergibt die fehlerhafte virtuelle Adresse, die Art Lesen/Schreiben/Ausführen, Benutzer/Kernel und ob die Ursache eine fehlende Übersetzung oder ein Schutzverstoß ist an den Kernel.
  3. Der Speicher-Manager prüft VAD und PTE.
    Er entscheidet, ob die Seite committet ist, ob der Zugriff dem Schutz entspricht, und welche von Demand-Zero, Transition, gemeinsam genutzt, Page-in, CoW oder Ausnahme gilt.
  4. Bei Demand-Zero wird eine genullte physische Seite geholt.
    Eine neu ausgegebene Seite muss null sein, damit Daten eines anderen Prozesses nicht durchsickern.
  5. PTE und PFN-Verwaltungsinformationen werden aktualisiert.
    PFN und Schutz werden in der PTE gesetzt, die physische Seite wird Active, und sie wird ins Working Set des Prozesses aufgenommen.
  6. Der fehlgeschlagene Befehl wird erneut ausgeführt.
    Weil der Fault normal aufgelöst wurde, kommt keine Benutzermodus-Ausnahme an, und die App fährt fort, als wäre es eine gewöhnliche Zuweisung.

Auch ETW-Ereignisse zu Page Faults zeichnen Transition, Demand Zero, Copy-on-Write, Guard Page, Hard Page Fault und Access Violation als eigene Arten auf.4

Ein Page Fault bedeutet also von vornherein nicht „anormal“. Er ist der gemeinsame Einstieg, mit dem die CPU das Betriebssystem um eine Entscheidung bittet, wenn sie auf dem gewöhnlichen Weg nicht übersetzen konnte.

Wohin ein Page Fault aufgelöst wirdDer Speicher-Manager bewertet VAD, PTE, Schutzattribute und Zugriffsart und verteilt auf Demand-Zero, erneutes Anbinden einer noch im RAM liegenden Seite, Hard Page Fault vom Backing Store, Copy-on-Write, Guard-Seiten-Benachrichtigung oder AusnahmeErster ZugriffNoch im RAMDatenträgerlesen nötigCoW-SchreibenGuard-SeiteNicht auflösbarPage Fault tritt aufVAD, PTE, Schutz und Art bewertenDemand-Zero (soft)Aus Standby u. a. erneut anbinden (soft)Hard Page Fault (Datenträger-E/A)Kopieren und die PTE austauschenGuard aufheben und benachrichtigenAusnahme (0xC0000005 u. a.)

Abbildung 4: Faults, die denselben Einstieg nehmen, teilen sich je nach Bewertung in sechs Arten von Ausgang. Guard-Seiten behandelt Abschnitt 9 ausführlich.

7. Demand-Zero — ein Soft Page Fault, der nicht von Datenträger liest

Demand-Zero ist der typische Soft Page Fault, der entsteht, wenn eine committete private Seite zum ersten Mal berührt wird. Auch Microsofts Erläuterung zum Working Set nennt den Fall, „dass ein Prozess eine zugewiesene virtuelle Seite zum ersten Mal referenziert“, als Beispiel für einen Soft Page Fault.5

Demand-Zero hat die folgenden Merkmale.

  • Ursprüngliche Daten müssen nicht vom Datenträger gelesen werden
  • Der Anfangsinhalt ist null
  • Eine verfügbare physische Seite wird gebunden
  • Working Set und der kumulierte Page Fault Count steigen
  • Diese Behandlung allein erhöht Memory\\Pages Input/sec nicht

Deshalb bedeutet ein Sprung von Page Faults/sec direkt nach dem Start nicht von selbst, dass der Speicher überlastet ist.

7.1. Verzögerte Zuweisung tauscht RAM gegen Kosten des ersten Zugriffs

Wenn Sie 256MiB committen, aber nur 8MiB wirklich nutzen, ist die verzögerte Zuweisung, die die restlichen 248MiB nicht ins RAM legt, vernünftig. Im Gegenzug trägt der erste Zugriff die Kosten der Fault-Behandlung.

Bei latenzkritischer Verarbeitung wählen Sie manchmal ein „Prefault“, das vor dem Start jede Seite berührt. Das ist jedoch keine kostenlose Optimierung. Es ist die Entscheidung, die Behandlung des ersten Zugriffs vorzuziehen und dafür auch die RAM-Residenz vorzuziehen.

8. Soft Page Faults und Hard Page Faults

Die Grenze ist, ob eine Lese-E/A vom Backing Store nötig ist. Die Zahl der Page Faults allein zeigt diesen Unterschied nicht.

8.1. Soft Page Faults

Ein Soft Page Fault ist ein Fault, der ohne Lese-E/A zum Backing Store auflösbar ist. Typische Beispiele sind die folgenden.

  • Demand-Zero
  • Erneutes Anbinden einer Seite, die auf Standby/Transition bleibt
  • Anbinden einer gemeinsam genutzten Seite im Working Set eines anderen Prozesses
  • Anbinden einer bereits vorausgelesenen Seite
  • Copy-on-Write, dessen Ursprungsseite resident ist

Kernelübergang, Sperren, PTE/PFN-Aktualisierung, TLB-Kohärenz und Ähnliches kosten CPU, aber es gibt keine Speicherwartezeit.5

8.2. Hard Page Faults

Wenn die benötigte Seite nirgendwo im RAM liegt und vom Backing Store gelesen werden muss, ist das ein Hard Page Fault. Die Lesequelle ist dabei nicht nur die Auslagerungsdatei.

  • Eine private Seite, die in die Auslagerungsdatei ausgelagert wurde
  • Eine speicherabgebildete Datei
  • Ein EXE- oder DLL-Image
  • Eine Datendatei, auf die der Dateicache verweist

ETW-HardFault-Ereignisse enthalten FileObject, ReadOffset und ByteCount, sodass sich die tatsächliche Lesequelle verfolgen lässt.6

Hard Fault = pagefile.sys gelesen gilt also nicht.

Wird ein Lesen vom Backing Store nötig, tritt die Anforderung in den Windows-E/A-Stapel ein. Den Ablauf von IRP sowie Ausgabe und Abschluss behandelt „Die Tiefen von Windows I/O (Teil 1)“, den Zusammenfluss mit dem Dateicache „Die Tiefen von Windows I/O (Teil 4)“. Liegt die Seite im RAM, kann der Speicher-Manager allein zurückkehren; sonst gibt er E/A aus und lässt den fehlerhaften Thread bis zum Abschluss warten.

9. Ein nicht auflösbarer Fault wird zur Ausnahme

Ein Fault, der sich auch nach Prüfung von VAD und PTE nicht als zulässige Zuweisung, Page-in oder CoW auflösen lässt, kommt als Ausnahme in den Benutzermodus.

9.1. Wenn es zur Zugriffsverletzung wird

Der typische Fall ist STATUS_ACCESS_VIOLATION, Ausnahmecode 0xC0000005. Er entsteht beim Lesen, Schreiben oder Ausführen einer ungültigen Adresse; der erste Ausnahmeparameter zeigt die Zugriffsart, der zweite die verletzende Adresse.7

Typische Entstehungsmuster sind die folgenden.

  • NULL, eine bereits freigegebene Adresse oder eine Adresse außerhalb eines Arrays lesen
  • Auf eine schreibgeschützte Seite schreiben
  • Einen Befehl von einer Seite ausführen, die DEP/NX nicht ausführbar gemacht hat
  • Einen nur reservierten, nicht committeten Bereich berühren

9.2. Eine Guard-Seite dient als einmalige Benachrichtigung

PAGE_GUARD hat eine etwas andere Bedeutung. Es ist ein Mechanismus, der einen Zugriff genau einmal meldet, STATUS_GUARD_PAGE_VIOLATION auslöst und etwa zur Stackerweiterung dient.8

Normale verzögerte Zuweisung, Page-in, CoW, Guard-Benachrichtigung und die endgültige Zugriffsverletzung treffen aus Sicht der CPU am selben Einstieg des Page Fault zusammen. Den Ausgang entscheidet die Kombination aus VAD, PTE, Schutzattributen und Zugriffsart.

10. Selbst nachprüfen

Ziel des Experiments ist, die Stufe, in der Commit steigt, und die Stufe, in der das Working Set steigt, getrennt zu beobachten.

Das folgende C++-Programm reserviert 256MiB, committet sie, schreibt ein Byte auf jede Seite und gibt sie schließlich frei. In jeder Stufe wartet es auf die Eingabetaste, sodass Sie dort die Werte in VMMap und PerfMon prüfen können.

#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");
}

In der x64 Native Tools Command Prompt von Visual Studio können Sie mit dem folgenden Befehl bauen.

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

10.1. Was Sie in VMMap ansehen

VMMap ist ein Werkzeug, das reservierten virtuellen Speicher, Commit, Working Set, Private und Shareable nach Art anzeigt.9 Die in jeder Stufe zu erwartende Veränderung ist die folgende.

Stufe Erwartete Veränderung
Reserve Die Size des Address Space steigt, Commit/WS steigen aber nicht um denselben Betrag
Commit Das Private-Commit steigt um etwa 256MiB
Touch Working Set und Private WS steigen deutlich, und auch der Fault Count steigt
Release Der Zielbereich verschwindet, Commit und WS sinken

Nicht auf übereinstimmende Zahlen, sondern auf die Veränderung zwischen den Stufen achten

Die tatsächlichen Zahlen ändern sich mit Laufzeit, Sicherheitsprodukten, Speicherdruck und Beobachtungszeitpunkt. Achten Sie nicht darauf, ob es genau 256MiB sind, sondern in welche Richtung sich die Zahlen zwischen den Stufen bewegt haben.

10.2. Soft und Hard in PerfMon trennen

In PerfMon legen Sie die folgenden Zähler auf dieselbe Zeitachse.

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

Process\\Page Faults/sec enthält Soft- und Hard-Faults. Memory\\Pages Input/sec dagegen ist die Zahl der Seiten, die zur Auflösung von Hard Page Faults vom Datenträger gelesen wurden.10

In der Touch-Stufe dieses Programms sollte Page Faults/sec springen, Pages Input/sec aber nicht stark steigen. Neu committete Seiten werden per Demand-Zero materialisiert, sodass ursprüngliche Daten nicht vom Datenträger gelesen werden müssen.

Prozesse gleichen Namens auch per PID prüfen

Gibt es mehrere Prozesse gleichen Namens, können sich Nummern wie process#1 in PerfMon nach einem Neustart ändern. Gleichen Sie mit einem Zähler ab, der die PID anzeigt, oder identifizieren Sie den Prozess per PID mit Process V2 oder ETW/WPA.

11. Drei Fehldeutungen, die Sie in der Praxis vermeiden sollten

11.1. „Commit ist gestiegen, also RAM-Leck“

Commit ist die versprochene Menge zum Halten des Inhalts, und unberührte Seiten müssen nicht im RAM resident sein. Zur Beurteilung eines Lecks sehen Sie den Zeitverlauf der Private Bytes, die Aufschlüsselung der Zuweisungen und ob der Wert nach der Verarbeitung zur Basis zurückkehrt.

11.2. „Page Faults/sec ist hoch, also ist der Datenträger langsam“

Soft Page Faults gehen ohne Datenträger-E/A. Sehen Sie Page Faults/sec, Pages Input/sec und die Speicherwartezeit getrennt, und verfolgen Sie bei Bedarf mit ETW-HardFault-Ereignissen die Quelldatei und den Stapel.

11.3. „Wenn ich das Working Set leere, ist das Leck behoben“

Das Entfernen aus dem Working Set gibt weder Commit noch Besitz frei. Die Seiten wandern nach Standby oder Modified und kommen später per Fault zurück. Ein Leck beheben Sie, indem die zuweisende Stelle VirtualFree, eine Heap-Freigabe, die Zerstörung eines Objekts oder Ähnliches ausführt.

Wohin die entfernte physische Seite geht, verfolgt Teil 2.

12. Zusammenfassung

  • MEM_RESERVE beansprucht einen virtuellen Adressbereich, weist aber keinen physischen Bereich in RAM oder Auslagerungsdatei zu.1
  • MEM_COMMIT verbraucht Commit und garantiert, dass der Inhalt künftig gehalten werden kann, aber eine gewöhnliche physische Seite wird erst beim ersten Zugriff zugewiesen.12
  • Der VAD ist das Verzeichnis der Bereiche, die PTE das der virtuellen Seiten, die PFN-Datenbank das der physischen Seiten.
  • Ein TLB-Miss ist kein Page Fault. Gibt es eine gültige PTE, löst ein Page-Table-Walk ihn allein.
  • Demand-Zero, Transition-Wiederherstellung und das Anbinden einer gemeinsam genutzten Seite sind Soft Page Faults, die ohne Datenträger-E/A auflösbar sind.5
  • Ist ein Lesen aus Auslagerungsdatei, DLL, EXE oder einer zugeordneten Datei nötig, ist es ein Hard Page Fault.6
  • Lässt sich der Fault nach Prüfung von VAD, PTE und Schutzattributen nicht auflösen, wird er zu einer Ausnahme wie 0xC0000005.7
  • Für eine Leistungsbeurteilung sehen Sie nicht Page Faults/sec allein, sondern Pages Input/sec, Available, Working Set, Private Bytes und die Speicherwartezeit auf derselben Zeitachse.

Weiter in Teil 2, „Das Leben einer physischen Seite: fünf Listen und die Wahrheit über die Auslagerungsdatei“.

Nachdem das Versprechen Commit in eine physische Seite verwandelt wurde, verfolgen wir anhand der PFN-Datenbank und der Seitenlisten, wohin diese Seite geht, sobald sie das Working Set verlässt.

Verwandte Artikel

Verwandte Beratungsfelder

Die KomuraSoft LLC übernimmt Untersuchungen des Speicherverbrauchs von Windows-Anwendungen, Zugriffsverletzungen, Startverzögerungen, Paging und die Analyse von Fehlern in nativem Code.

Quellen

  1. Microsoft Learn, VirtualAlloc function. Dazu, dass MEM_RESERVE einen virtuellen Adressbereich ohne Zuweisung physischen Speichers reserviert, MEM_COMMIT eine Commit-Gebühr gegen den Gesamtspeicher und die Auslagerungsdatei des Systems erhebt, der Anfangsinhalt einer committeten Seite null ist und die tatsächliche physische Seite erst beim Zugriff zugewiesen wird. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  2. Microsoft Learn, PERFORMANCE_INFORMATION structure. Dazu, dass CommitTotal die aktuelle Zahl committeter Seiten im System ist und CommitLimit die Obergrenze, die ohne Erweiterung der Auslagerungsdatei committet werden kann. ↩ ↩2 ↩3

  3. Microsoft Learn, !vad (WinDbg). Dazu, dass !vad den VAD-Baum anzeigt und Start- und End-VPN, Commit, Mapped/Private, Schutzattribute, Control Area und mehr prüfen lässt. ↩

  4. Microsoft Learn, PageFault_TypeGroup1 class. Dazu, dass ETW Transition Fault, Demand Zero Fault, Copy-on-Write, Guard Page Fault, Hard Page Fault und Access Violation unterscheidet und aufzeichnet. ↩

  5. Microsoft Learn, Working Set. Dazu, dass ein Soft Page Fault ohne Zugriff auf einen Backing Store auflösbar ist und aus dem Working Set eines anderen Prozesses, Transition, Demand-Zero beim ersten Referenzieren und Ähnlichem entsteht. ↩ ↩2 ↩3

  6. Microsoft Learn, PageFault_HardFault class. Dazu, dass ein HardFault-Ereignis FileObject, ReadOffset, ByteCount, VirtualAddress und eine Thread-ID enthält, sodass sich die Lesequelle verfolgen lässt. ↩ ↩2

  7. Microsoft Learn, Access Violation C0000005. Dazu, dass 0xC0000005 beim Lesen, Schreiben oder Ausführen einer ungültigen Speicheradresse entsteht und die Ausnahmeparameter Zugriffsart und verletzende Adresse anzeigen. ↩ ↩2

  8. Microsoft Learn, Creating Guard Pages. Dazu, dass PAGE_GUARD eine einmalige Benachrichtigung über einen Seitenzugriff bereitstellt und STATUS_GUARD_PAGE_VIOLATION auslöst. ↩

  9. Microsoft Learn, VMMap - Sysinternals. Dazu, dass VMMap committeten virtuellen Speicher nach Art zerlegt und Working Set sowie eine detaillierte Adresskarte je Art anzeigt. ↩

  10. Microsoft Learn, Performance Analysis of Logs (PAL) Tool. Dazu, dass Memory\\Pages Input/sec die Zahl der Seiten ist, die zur Auflösung von Hard Page Faults vom Datenträger gelesen wurden. ↩

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Weist VirtualAlloc mit MEM_COMMIT in diesem Moment RAM zu?
Im gewöhnlichen privaten Speicher verbraucht Commit den Commit-Spielraum des Systems, die zugehörige physische Seite wird aber erst beim ersten Zugriff zugewiesen. Eine Seite, die zuerst durch einen Schreibzugriff berührt wird, erhält ihre physische Seite während der Behandlung eines Demand-Zero-Faults.
Bedeutet ein Page Fault, dass etwas falsch ist oder ein Leistungsproblem vorliegt?
Nein. Soft Page Faults ohne Datenträger-E/A — etwa Demand-Zero oder die Rückkehr einer Seite aus Standby — sind Normalbetrieb. Für eine Leistungsbeurteilung sehen Sie nicht nur Page Faults/sec, sondern auch Pages Input/sec, die Speicherwartezeit und Available MBytes.
Sind ein TLB-Miss und ein Page Fault dasselbe?
Sie sind verschieden. Auch wenn der TLB keine Übersetzung hat, läuft die CPU bei gültiger PTE der Seitentabelle lediglich die Tabelle ab und trägt die Übersetzung neu ein. Zum Einstiegspunkt des Page Fault geht es, wenn die PTE ungültig ist oder ein Schutzverstoß vorliegt.
Kann man keine Zugriffsverletzung bekommen, wenn der Adressbereich in einem VAD liegt?
Nicht unbedingt. Neben der Existenz eines VAD bewertet der Speicher-Manager Reserve gegenüber Commit, Lese-/Schreib-/Ausführungsschutz, Guard-Seiten, den PTE-Zustand und mehr. Lässt sich der Fault nicht auflösen, erhalten Sie eine Ausnahme wie 0xC0000005.
Bedeutet ein hohes Page Faults/sec, dass dem System RAM fehlt?
Das allein sagt das nicht. Page Faults/sec enthält auch eine große Zahl von Soft Page Faults. Sie müssen es auf derselben Zeitachse mit Memory\Pages Input/sec, Memory\Page Reads/sec, Available MBytes und der Datenträgerwartezeit korrelieren.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog