Was bedeutet Windows' „Speicherauslastung“ eigentlich? — Working Set, Private Bytes, Commit und die Auslagerungsdatei richtig lesen
· Go Komura · Windows, Windows-Entwicklung, Speicherverwaltung, Working Set, Private Bytes, Commit, Auslagerungsdatei, Leistungsüberwachung, Fehlersuche, Sysinternals
Im Task-Manager zeigt der „Speicher“ eines Prozesses 1,2GB an. Process Explorer zeigt jedoch ein Working Set von 1,5GB und Private Bytes von 2,4GB, und VMMap weist unter „Size“ einen noch größeren Wert aus. Betrachtet man das gesamte System, steht dort „Committed 19,6/31,8GB“.
Wie viele Gigabyte Speicher verbraucht diese Anwendung nun also tatsächlich?
Die Antwort lautet: Welche Zahl relevant ist, hängt davon ab, was Sie eigentlich wissen wollen. Ob Sie die derzeit im RAM liegende Menge wissen möchten, die diesem Prozess spezifisch zugewiesene Menge, die Menge, die das System auch künftig zu stützen verspricht, oder schlicht den Bereich der reservierten virtuellen Adressen — je nachdem ist ein anderer Indikator maßgeblich.
Was Windows-Speicherkennzahlen schwer verständlich macht, ist, dass sie alle unter demselben Wort „Speicher“ angezeigt werden, obwohl sie tatsächlich die folgenden getrennten Achsen messen.
- Wie viel Adressraum genutzt wird
- Wie viel Commit verbraucht wurde
- Ob etwas derzeit im physischen RAM resident ist
- Ob die Seite prozessspezifisch oder gemeinsam nutzbar ist
- Wie viel Zuweisung das System insgesamt noch stützen kann
Dieser Artikel richtet sich an alle, die unter Windows 10/11 und aktuellem Windows Server wachsenden App-Speicherverbrauch oder systemweite Speicherengpässe untersuchen, und verbindet die Beziehungen zwischen Working Set, Private Working Set, Private Bytes, Commit, Virtual Bytes, der Auslagerungsdatei, Available und Page Faults zu einem Gesamtbild.
Das Vorgehen zur Ursachensuche, warum .NET-Objekte nicht eingesammelt werden, wird ausführlich in „GC-Wartezeit von einem Speicherleck in .NET unterscheiden“ behandelt, die konkrete Bedienung von VMMap und Process Explorer in „Process Explorer / Handle / VMMap in der Praxis“. Dieser Artikel konzentriert sich auf die dafür nötige Voraussetzung: das Lesen der Zahlen auf Seiten des Windows-Betriebssystems.
1. Das Wichtigste zuerst
- Working Set sind die Seiten, die derzeit im RAM resident sind. Dazu zählen nicht nur prozessspezifische Seiten, sondern auch mit anderen Prozessen teilbare Seiten wie DLL-Code oder speicherabgebildete Dateien.1
- Private Working Set ist der Teil des Working Set, der derzeit ausschließlich diesem Prozess gehört. Es eignet sich als Näherung für „das RAM, das dieser Prozess gerade allein belegt“, ist aber nicht die gesamte von der App zugewiesene Menge.2
- Private Bytes ist die diesem Prozess eigene Commit-Menge. Das ist ein von der aktuellen RAM-Residenz unabhängiger Indikator. Auch das Feld
PagefileUsagein der Win32-API-Struktur stellt unter heutigem Windows praktisch dieselbe Commit Charge dar und ist nicht die Anzahl der tatsächlich in die Auslagerungsdatei geschriebenen Bytes.2 - „Committed X/Y“ im Task-Manager zeigt bei X die aktuelle systemweite Commit-Menge und bei Y die Commit-Obergrenze. X ist nicht die Nutzung der Auslagerungsdatei. Y ergibt sich grob aus RAM plus Auslagerungsdatei.3
- Reserve und Commit sind unterschiedliche Dinge. Wird ein virtueller Adressbereich nur reserviert (Reserve), wird er lediglich für eine künftige Nutzung vorgemerkt und verbraucht weder RAM noch Commit-Obergrenze in gleicher Höhe.45
- Ein Page Fault bedeutet nicht zwangsläufig Datenträger-I/O. Es gibt Soft Faults, die sich innerhalb des RAM auflösen lassen, und Hard Faults, die aus der Auslagerungsdatei, ausführbaren Dateien, speicherabgebildeten Dateien und Ähnlichem lesen.16
- Ein Speicherleck wird nicht anhand eines einzelnen Werts beurteilt, sondern anhand des Trends bei wiederholter gleicher Last. Prüfen Sie insbesondere, ob Private Bytes und dessen Aufschlüsselung nach Abschluss der Verarbeitung schrittweise weiter ansteigen, ohne in denselben stationären Zustand zurückzukehren.
In einem Satz zusammengefasst: Working Set ist „die Menge, die gerade im RAM liegt“, Private Bytes ist „die diesem Prozess speziell versprochene Menge“, und Commit ist „die vom gesamten System versprochene Menge“.
flowchart TB
accTitle: Die richtige Windows-Speicherkennzahl wählen
accDescr: Welche Kennzahl relevant ist, hängt davon ab, ob RAM-Residenz, prozessspezifisches Commit, systemweites Commit oder virtueller Adressbereich von Interesse ist
question["Was möchten Sie über die Speichernutzung wissen"]
question -->|Menge, die gerade im RAM liegt| workingSet["Working Set"]
question -->|prozessspezifisch versprochene Menge| privateBytes["Private Bytes"]
question -->|systemweit versprochene Menge| systemCommit["System Commit"]
question -->|reservierter Adressbereich| virtualBytes["Virtual Bytes / Reserved"]
workingSet --> resident["Residenz im physischen RAM"]
privateBytes --> privateCommit["Prozessspezifisches Commit"]
systemCommit --> commitLimit["Vergleich mit Commit Limit"]
virtualBytes --> addressSpace["Virtueller Adressraum"]
Abbildung 1: Die Beobachtung „der Speicher ist hoch“ zunächst in vier getrennte Fragen zerlegen.
2. „Speichernutzung“ in vier Achsen aufteilen
Betrachten Sie Windows-Speicher zunächst nicht als „einen einzigen Balken“, sondern entlang von vier Achsen.
flowchart TB
accTitle: Vier unabhängige Achsen zur Einordnung einer einzelnen Seite
accDescr: Adresszustand, Absicherung committeter Seiten, Residenz im physischen RAM und Teilbarkeit mit anderen Prozessen getrennt betrachten
page["Eine Seite entlang vier Achsen betrachten"]
page --> address["Adresszustand"]
address --> addressValues["Free / Reserved / Committed"]
page --> backing["Absicherung"]
backing --> backingValues["Page-file-backed / File-backed"]
page --> residentAxis["RAM-Residenz"]
residentAxis --> residentValues["Resident / Nicht resident"]
page --> sharing["Teilbarkeit"]
sharing --> sharingValues["Private / Shareable"]
Abbildung 2: Auch bei einer einzelnen Seite werden Adresszustand, Absicherung, Residenz und Teilbarkeit jeweils unabhängig bestimmt.
Mapped ist kein Adresszustand neben Free, Reserved und Committed, sondern eine Art von Bereich. Auch Seiten einer Mapped View können Committed sein. Ebenso ist Private kein Absicherungsmedium, sondern eine Klassifizierung der Teilbarkeit. Lesen Sie daher die Absicherung getrennt als Page-file-backed oder File-backed und die Teilbarkeit getrennt als Private oder Shareable.
Kombiniert man diese vier Achsen, ergibt sich folgender Zusammenhang zwischen den wichtigsten Kennzahlen.
| Seitenzustand | Working Set | Private Working Set | Private Bytes | Virtual-Bytes-Familie |
|---|---|---|---|---|
| Prozessspezifisch, committet, RAM-resident | Enthalten | Enthalten | Enthalten | Enthalten |
| Prozessspezifisch, committet, nicht RAM-resident | Nicht enthalten | Nicht enthalten | Enthalten | Enthalten |
| Gemeinsame Seite einer DLL oder Mapped File, RAM-resident | Enthalten | In der Regel nicht enthalten | In der Regel nicht enthalten | Enthalten |
| Reserviert, aber nicht committet | Nicht enthalten | Nicht enthalten | Nicht enthalten | Kann enthalten sein |
| Ungenutzter Adressbereich | Nicht enthalten | Nicht enthalten | Nicht enthalten | Normalerweise nicht enthalten |
flowchart TB
accTitle: Zuordnung von Seitentypen zu den wichtigsten Speicherkennzahlen
accDescr: Zeigt, welche Kennzahlen residente private Seiten, nicht-residente private Seiten, residente gemeinsame Seiten und nur reservierte Bereiche einschließen
privateResident["Private, committet, RAM-resident"]
privateNonresident["Private, committet, nicht RAM-resident"]
sharedResident["Gemeinsame Seite, RAM-resident"]
reservedOnly["Reserviert, nicht committet"]
workingSet["Working Set"]
privateWorkingSet["Private Working Set"]
privateBytes["Private Bytes"]
virtualBytes["Virtual-Bytes-Familie"]
privateResident --> workingSet
privateResident --> privateWorkingSet
privateResident --> privateBytes
privateResident --> virtualBytes
privateNonresident --> privateBytes
privateNonresident --> virtualBytes
sharedResident --> workingSet
sharedResident --> virtualBytes
reservedOnly --> virtualBytes
Abbildung 3: Working Set und Private Bytes zählen unterschiedliche Mengen von Seiten und stehen daher nicht in einer einfachen Enthaltenseinsbeziehung.
Wichtig ist hier, dass Working Set und Private Bytes nicht in einer einfachen Enthaltenseinsbeziehung stehen.
Private Bytes umfasst Seiten, die prozessspezifisch sind, aber derzeit nicht im RAM resident sind. Working Set dagegen umfasst gemeinsame Seiten — etwa DLL-Code oder gemeinsamen Speicher —, die Private Bytes überhaupt nicht mitzählt. Je nach Prozess und Zeitpunkt kann daher Working Set größer sein als Private Bytes, oder umgekehrt.
Summiert man außerdem einfach die Working Sets mehrerer Prozesse, kann dieselbe physische Seite — etwa einer gemeinsam genutzten DLL — mehrfach gezählt werden. „Die Summe der Working Sets aller Prozesse entspricht dem genutzten RAM“ trifft also nicht zwangsläufig zu.
3. Virtueller Adressraum — Reserve und Commit sind unterschiedliche Dinge
3.1. Eine virtuelle Adresse ist keine physische RAM-Adresse
Jeder Prozess besitzt einen eigenen virtuellen Adressraum. Ein Zeiger, mit dem eine App arbeitet, gibt nicht direkt eine Position im physischen RAM an; Windows bildet über Seitentabellen virtuelle Adressen auf physische Seiten oder auf Daten in einer Datei ab.7
Dadurch kann selbst auf einem PC mit 64GB installiertem RAM der virtuelle Adressraum, den ein bestimmter 32-Bit-Prozess nutzen kann, normalerweise weit kleiner sein. Umgekehrt ist es ebenso normal, dass ein 64-Bit-Prozess einen größeren virtuellen Adressraum besitzt als physisch vorhandenes RAM.
3.2. Reserved bedeutet nur „die Adresse ist vorgemerkt“
MEM_RESERVE bei VirtualAlloc reserviert einen zusammenhängenden virtuellen Adressbereich für eine künftige Nutzung. In diesem Stadium ist den Seiten kein physischer Speicher zugeordnet, und der Bereich lässt sich weder lesen noch beschreiben.45
Reserviert beispielsweise eine Datenbank oder Laufzeitumgebung einen 8GB großen Adressbereich für künftiges Wachstum, verbraucht das allein weder 8GB RAM noch 8GB Private Bytes.
3.3. Committed ist das Versprechen, „bei Bedarf zu stützen“
MEM_COMMIT ist der Vorgang, der eine virtuelle Seite in den Zustand Committed versetzt und Windows verspricht, die nötige Absicherung bereitzustellen. Ob tatsächlich Lesen, Schreiben oder Ausführen erlaubt ist, wird separat über den Seitenschutz bestimmt — PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_NOACCESS und Ähnliches —, sodass „Committed“ allein nicht „lesbar und beschreibbar“ bedeutet. Im Moment des Committens wird die Seite auf die Commit Charge des Systems angerechnet, aber die tatsächliche physische Seite wird unter Umständen erst beim ersten Zugriff zugewiesen. Eine erstmals berührte Seite wird nullinitialisiert, durchläuft einen Demand-Zero Fault und gelangt so ins Working Set.51
Auch wenn beides als „reserviert/zugewiesen“ bezeichnet wird, gibt es also folgende drei Stufen.
flowchart TB
accTitle: Drei Stufen von Reserve über Commit bis zur RAM-Residenz
accDescr: Zeigt den Ablauf, bei dem eine virtuelle Adresse reserviert, eine Seite committet und beim ersten Zugriff eine physische Seite zugewiesen wird und ins Working Set gelangt
reserve["MEM_RESERVE: Adressbereich reservieren"]
reserve -.-> virtualMetric["Wirkt sich auf die Virtual-Bytes-Familie aus"]
reserve -->|MEM_COMMIT| committed["Committet: zugänglich je nach Seitenschutz"]
committed -.-> commitMetric["Wirkt sich auf Private Bytes / System Commit aus"]
committed -->|Erster Zugriff, Demand-Zero Fault| resident["Physische Seite zugewiesen, RAM-resident"]
resident -.-> workingSetMetric["Wirkt sich auf Working Set aus"]
committed -.->|Falls nie zugegriffen| nonresident["Committet, aber nicht resident"]
Abbildung 4: Reserve, Commit und der erste Zugriff sind getrennte Ereignisse, die jeweils eine andere Kennzahl bewegen.
Diese drei Stufen bewegen die Zahlen der Virtual-Bytes-Familie, von Private Bytes und von Working Set jeweils getrennt.
3.4. Warum OutOfMemory auch bei freiem RAM auftreten kann
Ob eine Speicherzuweisung gelingt, hängt nicht allein vom freien RAM ab.
- Der virtuelle Adressraum des Prozesses ist erschöpft
- Es gibt keinen zusammenhängenden freien Adressbereich in der benötigten Größe
- Die systemweite Commit Charge hat das Commit Limit erreicht
- Ein Job-Objekt, ein Container, eine Laufzeitumgebung oder eine Bibliothek hat eine eigene Obergrenze
- Es handelt sich um einen 32-Bit-Prozess
- Der native Heap ist fragmentiert
Auch unter 64-Bit-Windows ist der virtuelle Adressraum eines 32-Bit-Prozesses im Benutzermodus normalerweise auf 2GB begrenzt, wenn IMAGE_FILE_LARGE_ADDRESS_AWARE nicht gesetzt ist. Eine 32-Bit-App mit gesetztem Flag kann unter 64-Bit-Windows bis zu 4GB nutzen.8
„Der PC hat 20GB freien RAM, und trotzdem scheitert die 32-Bit-App bei rund 1,6GB“ ist daher kein Widerspruch. Es muss sich nicht um ein RAM-Problem handeln, sondern kann an Fragmentierung des Adressraums oder an einer erreichten Obergrenze liegen.
4. Working Set — die Seiten, die gerade im RAM liegen
Working Set ist die Menge der Seiten innerhalb des virtuellen Adressraums eines Prozesses, die derzeit im physischen RAM resident sind.1
Darin mischen sich folgende Bestandteile.
- Der prozesseigene Heap und Stack
- Code und schreibgeschützte Daten von EXE und DLLs
- Speicherabgebildete Dateien
- Gemeinsamer Speicher
- Seiten, die nach Copy-on-Write prozesseigen wurden
- Von der Laufzeitumgebung und verschiedenen Bibliotheken berührte Seiten
4.1. Ein wachsendes Working Set bedeutet nicht zwangsläufig eine größere Zuweisung
Wird eine bereits committete Seite erstmals aufgerufen, kann allein das Working Set wachsen, während Private Bytes unverändert bleibt. Wird eine große Datei speicherabgebildet und der Reihe nach gelesen, gelangen ebenso dateibasierte Seiten ins Working Set, während Private Bytes kaum zunimmt.
Trimmt Windows umgekehrt das Working Set aufgrund von Speicherdruck, sinkt allein das Working Set, während die App logisch weiterhin denselben Speicher hält. Wird später erneut darauf zugegriffen, kehrt es über einen Page Fault zurück.
Ein Rückgang des Working Set bedeutet daher nicht zwangsläufig, „die App hat freigegeben“, und ein Anstieg nicht zwangsläufig, „die App hat neu zugewiesen“.
flowchart TB
accTitle: Ein typischer Ablauf, bei dem nur das Working Set steigt und sinkt
accDescr: Dieselbe committete Seite gelangt beim ersten Zugriff ins RAM, wird durch Trim nicht-resident und kehrt bei erneutem Zugriff zurück, während Private Bytes durchgehend angerechnet bleibt
committed["Dieselbe committete Seite"]
committed -->|Erster Zugriff| resident["RAM-resident"]
resident -->|Trim bei Speicherdruck| nonresident["Nicht resident"]
nonresident -->|Page Fault bei erneutem Zugriff| resident
resident -.-> inWorkingSet["Im Working Set enthalten"]
nonresident -.-> outsideWorkingSet["Nicht im Working Set enthalten"]
committed -.-> privateBytes["Solange committet, in Private Bytes angerechnet"]
Abbildung 5: Working Set steigt und sinkt mit dem Residenzstatus, aber Private Bytes sinkt nicht, solange das Commit derselben Seite bestehen bleibt.
4.2. Working Set enthält auch gemeinsame Seiten
Teilen sich 10 Prozesse dieselben Code-Seiten einer DLL, kann diese Seite im Working Set jedes einzelnen Prozesses erscheinen, obwohl im physischen RAM nur ein einziges Exemplar existiert. Übersteigt die Summe der Working Sets das installierte RAM, ist das nicht sofort ein Anzeichen für ein Problem.
Wer sich „dem RAM, das dieser Prozess gerade allein belegt“ annähern möchte, betrachtet Private Working Set. Aber auch das ist nicht „der gesamte von diesem Prozess zugewiesene Speicher“, sondern ausschließlich die derzeit residenten privaten Seiten.
4.3. Das erzwungene Verkleinern des Working Set behebt kein Leck
Mit EmptyWorkingSet oder SetProcessWorkingSetSize lassen sich Seiten aus dem Working Set eines Prozesses verdrängen. Das ist jedoch kein Vorgang, der Commit freigibt oder Referenzen auf dem Heap löst. Die scheinbare RAM-Nutzung sinkt, während Private Bytes unverändert bleibt, und beim nächsten Zugriff kann eine Welle von Page Faults auftreten.9
Sinkt die Zahl im Task-Manager nur unmittelbar nach dem Drücken einer Schaltfläche „Speicher reduzieren“ und steigt sie sofort wieder, sobald die Arbeit fortgesetzt wird, handelt es sich womöglich nur um ein Trim des Working Set und nicht um eine echte „Freigabe“.
5. Private Bytes — die einem Prozess eigene Commit-Menge
Private Bytes ist die Menge des virtuellen Speichers, der ausschließlich für diesen Prozess committet wurde. Es stellt eine Commit Charge dar, die nicht mit einem anderen Prozess geteilt werden kann, unabhängig davon, ob sie derzeit im RAM resident ist. In Microsofts PROCESS_MEMORY_COUNTERS_EX entspricht PrivateUsage diesem Wert.102
Die Win32-API besitzt außerdem das verwirrend benannte Feld PagefileUsage, das die aktuelle Dokumentation jedoch als „die Commit Charge dieses Prozesses“ definiert und als denselben Wert wie PrivateUsage beschreibt. Mit anderen Worten: Private Bytes von 2GB bedeutet nicht, dass „2GB in pagefile.sys geschrieben wurden“.2
Auf Private Bytes wirken sich typischerweise folgende Punkte aus.
- Das Commit des nativen Heaps, den
HeapAlloc,malloc,newund Ähnliches nutzen - Private Data, die direkt mit
VirtualAlloccommittet wurde - Der committete Bereich des .NET-GC-Heaps
- Der tatsächlich committete Teil eines Thread-Stacks
- Die Commit Charge für die gesamte View, die beim Mappen einer Copy-on-Write-View (
FILE_MAP_COPY) reserviert wird - Private Puffer, die Bibliotheken oder Geräte-SDKs intern vorhalten
Bei einer mit FILE_MAP_COPY erzeugten Copy-on-Write-View kann jede einzelne Seite künftig privat werden, weshalb Windows bereits beim Mappen die Commit Charge reserviert, um die gesamte View über die Auslagerungsdatei absichern zu können. Dadurch können System Commit und die Commit Charge des Prozesses (Private Bytes) um den Umfang der gesamten View steigen, noch bevor durch einen tatsächlichen Schreibzugriff eine private Kopie entsteht.11
5.1. Warum Private Bytes auch nach free oder einer GC nicht sinkt
Auch wenn Speicher aus Sicht der Anwendung „freigegeben“ wird, geben Laufzeitumgebung oder Heap-Allokator diesen Bereich mitunter nicht per Decommit an das Betriebssystem zurück, sondern behalten ihn zur späteren Wiederverwendung. In diesem Fall bleibt Private Bytes hoch, obwohl der Bereich intern in der App wiederverwendbar ist.
Auch Gründe wie das Überleben nur eines Teils eines großen Bereichs, Fragmentierung oder ein bis zur Obergrenze aufgewärmter Cache beziehungsweise Pool können zu einem dauerhaft hohen Wert führen.
Ein hoher Wert bei Private Bytes allein beweist daher kein Leck. Zu betrachten ist vielmehr ein Vergleich über die Zeit:
- Denselben Vorgang dieselbe Anzahl von Malen wiederholen
- Nach der Verarbeitung dieselbe Wartezeit einhalten
- Prüfen, ob Private Bytes auf denselben Stand zurückkehrt oder bei einem festen Wert stagniert
- Mit VMMap oder einem Heap-Dump prüfen, welcher Bereich oder Typ gewachsen ist
flowchart TB
accTitle: Warum Private Bytes auch nach free oder einer GC nicht sinkt
accDescr: Private Bytes verändert sich unterschiedlich, je nachdem ob der Allokator einen von der App nicht mehr benötigten Bereich an das Betriebssystem zurückgibt oder zur Wiederverwendung behält
release["App gibt einen Bereich per free / GC frei"]
release --> decision{"Gibt der Allokator ihn an das Betriebssystem zurück"}
decision -->|Decommit / Release| returned["Commit Charge sinkt"]
returned --> lower["Private Bytes sinkt"]
decision -->|Behält zur Wiederverwendung| retained["Bereich bleibt committet"]
retained --> high["Private Bytes stagniert hoch"]
retained --> reasons["Pools, Caches, Fragmentierung"]
Abbildung 6: Dass ein Bereich innerhalb der App wiederverwendbar wird, ist nicht dasselbe wie die Rückgabe seines Commits an das Betriebssystem.
5.2. Ein starkes Indiz für ein Leck
Ein Anstieg wie der folgende, bei dem sich die Untergrenze mit jeder Lastrunde treppenförmig nach oben verschiebt, verdient besondere Aufmerksamkeit.
Private Bytes
^
| ________
| ______|
| ______|
|_____|
+----------------------------> Wiederholungen desselben Vorgangs
Allerdings kann auch eine treppenförmige Kurve nur ein paar Runden Wachstum durch erstmaliges JIT, Schriftarten, Bilddecoder, Verbindungspools oder das Aufwärmen eines Caches darstellen, wonach sie sich stabilisiert. Entscheidend ist nicht dass ein Anstieg vorliegt, sondern dass kein stationärer Zustand erreicht wird.
6. System Commit — was „Committed X/Y“ tatsächlich bedeutet
Der Wert „Committed X/Y“ auf der Registerkarte [Leistung] → [Speicher] des Task-Managers ist eine systemweite Kennzahl.
- X: System Commit Charge — der committete Speicher, den Windows derzeit systemweit zu stützen verspricht
- Y: System Commit Limit — die Obergrenze des Commits, die das System stützen kann
Das Commit Limit ergibt sich grob aus dem physischen RAM zuzüglich der Summe aller Auslagerungsdateien. Ohne Auslagerungsdatei fällt es etwas kleiner aus als das installierte RAM.36
flowchart TB
accTitle: Der Zusammenhang zwischen System Commit Charge und Commit Limit
accDescr: Prozessspezifisches, gemeinsam genutztes und Kernel-Commit ergeben den aktuellen Wert X, während physisches RAM und Auslagerungsdatei die Obergrenze Y stützen
processCommit["Privates Commit jedes Prozesses"] --> charge["System Commit Charge: X"]
sharedCommit["Commit von durch die Auslagerungsdatei abgesicherten gemeinsamen Sections"] --> charge
kernelCommit["Commit des Kernels"] --> charge
physicalRam["Physisches RAM"] --> limit["System Commit Limit: Y"]
pageFiles["Auslagerungsdatei"] --> limit
charge -->|X kann Y nicht überschreiten| limit
Abbildung 7: X ist die aktuell versprochene Menge, Y die Obergrenze, die dieses Versprechen stützen kann — keine Anzeige der Nutzung der Auslagerungsdatei.
Zur System Commit Charge zählt nicht nur die Summe der Private Bytes aller Prozesse, sondern auch das Commit von über die Auslagerungsdatei abgesicherten gemeinsamen Sections sowie das vom Kernel verbrauchte Commit. Die Summe der prozessweisen Private Bytes allein kann X daher nicht vollständig erklären.
6.1. Commit Charge ist keine Nutzung der Auslagerungsdatei
Betrachten Sie ein System mit 16GB RAM, 16GB Auslagerungsdatei und Committed bei 20/31GB.
Diese 20GB bedeuten nicht, dass „20GB in die Auslagerungsdatei geschrieben wurden“. Die 20GB sind die Gesamtmenge, für die Windows verspricht, bei Bedarf RAM- oder Auslagerungsdatei-Absicherung bereitzustellen — etwa für private, veränderbare Seiten.
Zu diesem Zeitpunkt liegt eine Mischung folgender Zustände vor:
- Ein Großteil ist im RAM resident
- Ein Teil ist in die Auslagerungsdatei ausgelagert
- Manches ist committet, wurde aber noch nie erstmals aufgerufen
- Manches wird als Commit auf Kernelseite verbraucht
Möchten Sie die tatsächliche Nutzung der Auslagerungsdatei sehen, prüfen Sie getrennt von Commit Paging File(*)\% Usage. Allerdings erklärt auch Microsofts eigenes Material, dass eine hohe Nutzung der Auslagerungsdatei allein nicht zwangsläufig ein Leistungsproblem bedeutet und gemeinsam mit dem Erreichen des Commit Limit, der Modified Page List und der tatsächlichen Paging-I/O beurteilt werden sollte.6
6.2. Was passiert, wenn sich das System dem Commit Limit nähert
Erreicht die System Commit Charge das Commit Limit, können neue Commit-Anforderungen nicht mehr gestützt werden. Das führt zu fehlgeschlagenen Speicherzuweisungen von Prozessen, Absturz von Anwendungen und einem nicht mehr reagierenden System.3
Hier ist die X/Y-Relation des Commits wichtiger als „freies RAM“. Trimmen Sie Working Sets, um RAM freizugeben, löst das das Erreichen des Commit Limit nicht, solange die Commit Charge selbst nicht sinkt.
6.3. Die drei Aufgaben der Auslagerungsdatei
Die Auslagerungsdatei erfüllt hauptsächlich folgende Aufgaben.
- Das Commit Limit erweitern
- Das Auslagern selten genutzter, veränderter Seiten aus dem RAM ermöglichen
- Je nach Konfiguration das Systemabsturzabbild stützen
Das Deaktivieren der Auslagerungsdatei ist kein einfacher Fall von „die Datenträger-I/O sinkt zwangsläufig, und alles wird schneller“. Vielmehr senkt es das Commit Limit, macht es wahrscheinlicher, dass geänderte, aber momentan nicht benötigte Seiten im RAM verbleiben, und kann dazu führen, dass bei einem Absturz nicht das benötigte Abbild erfasst werden kann.36
Die passende Größe der Auslagerungsdatei lässt sich nicht allein aus dem installierten RAM ableiten. Auch Microsoft erklärt, dass sich dies nicht verallgemeinern lässt, da die Spitzen-System-Commit-Charge und die Art des benötigten Absturzabbilds von System zu System unterschiedlich sind.6
7. Die Zusammensetzung des physischen RAM — nicht allein an niedrigem Available urteilen
Physisches RAM wird nicht nur von den Working Sets der Benutzerprozesse verbraucht.
- Working Set jedes Prozesses
- Der System-Dateicache
- Seitenlisten wie Standby, Modified, Free und Zeroed
- Der Paged Pool / Nonpaged Pool des Kernels
- Von Gerätetreibern gehaltener Speicher
- Die Ablage der Speicherkomprimierung
- Mit GPU oder anderen Geräten gemeinsam genutzte oder für sie reservierte Bereiche
- Hardware-reservierter Speicher
7.1. Available umfasst auch wiederverwendbaren Cache
Windows’ Available MBytes ist nicht einfach vollständig ungenutztes RAM. Der Indikator umfasst neben Free und Zeroed auch Standby-Seiten, die bei Bedarf wiederverwendet werden können.12
- Free: Seiten, die derzeit keinem Zweck zugewiesen sind
- Zeroed: Seiten, die nullinitialisiert wurden, damit sie sicher an einen anderen Prozess übergeben werden können
- Standby: Seiten, die aus einem Working Set entfernt wurden, deren Inhalt aber weiterhin im RAM zwischengespeichert ist
- Modified: Seiten, deren Inhalt geändert wurde und die vor der Wiederverwendung in eine geeignete Absicherung zurückgeschrieben werden müssen
flowchart TB
accTitle: Die Bewegung zwischen Working Set und den Seitenlisten
accDescr: Zeigt, wie unveränderte Seiten nach Standby und geänderte Seiten nach Modified wechseln, gefolgt von erneutem Zugriff, Rückschreiben und Wiederverwendung
workingSet["Working Set: in Verwendung"]
workingSet -->|Unveränderte Seite entfernen| standby["Standby: Wiederverwendungskandidat mit erhaltenem Inhalt"]
workingSet -->|Geänderte Seite entfernen| modified["Modified: wartet auf Rückschreiben"]
modified -->|Rückschreiben abgeschlossen| standby
standby -->|Erneuter Zugriff| workingSet
standby -->|Für anderen Zweck wiederverwendet| reused["Für anderen Zweck zugewiesen"]
free["Free: ungenutzt"] -->|Nullinitialisierung| zeroed["Zeroed: für Neuzuweisung verfügbar"]
zeroed -->|Zugriff nach Zuweisung| workingSet
standby -.-> available["In Available enthalten"]
free -.-> available
zeroed -.-> available
Abbildung 8: Available umfasst nicht nur vollständig freien Speicher, sondern auch Standby, das bei Bedarf wiederverwendet werden kann.
„Um freies RAM zu vergrößern, den gesamten Cache zu verwerfen“ ist nicht immer von Vorteil. Liegen die benötigten Daten noch im Standby, kann ein erneuter Zugriff sie schnell zurück ins Working Set holen, ohne von der Festplatte zu lesen.
Ist daher im Task-Manager Free niedrig, Available aber ausreichend vorhanden, und treten keine Hard Faults oder Datenträgerwartezeiten als Problem auf, nutzt Windows das RAM womöglich lediglich effektiv als Cache.
7.2. Wenn RAM ohne große Prozesse schrumpft
Es ist nicht ungewöhnlich, dass sich der Speicherverbrauch selbst nach Summierung des Private Working Set jedes Prozesses nicht erklären lässt.
- Dateicache und speicherabgebildete Dateien
- Nonpaged Pool / Paged Pool
- Von einem Treiber gesperrte Seiten
- Gemeinsame Seiten
- Speicherkomprimierung
- Mit Virtualisierung oder der GPU zusammenhängende Zuweisungen
In diesem Fall prüfen Sie, statt weiter die Prozessliste zu betrachten, in Sysinternals’ RAMMap die Werte Use Counts, Processes, Priority Summary und File Summary. RAMMap ist das offizielle Werkzeug, um physischen Speicher nach Verwendungszweck, Seitenliste und Datei aufzuschlüsseln.13
Wächst allein der Nonpaged Pool immer weiter, ist das der Punkt, an dem eher ein Leck auf Treiber- oder Kernel-Seite zu vermuten ist als in den Private Bytes einer Anwendung im Benutzermodus.
8. Page Fault — ein hoher Wert allein ist keine Anomalie
Ein Page Fault tritt auf, wenn ein Prozess auf eine Seite zugreift, die sich derzeit nicht in seinem Working Set befindet. Trotz des Wortes „Fault“ im Namen handelt es sich nicht um einen außergewöhnlichen Fehler, sondern um den normalen Mechanismus, der virtuellen Speicher antreibt.1
8.1. Soft Faults
Diese lassen sich ohne Lesen von der Festplatte auflösen.
- Die Seite befindet sich noch in Standby oder Transition
- Dieselbe gemeinsame Seite liegt bereits im Working Set eines anderen Prozesses
- Eine committete Seite wird erstmals aufgerufen, und eine Nullseite wird zugewiesen
- Das Read-ahead des Speichermanagers hat sie bereits ins RAM geholt
Deshalb bedeutet ein hoher Wert bei \Memory\Page Faults/sec nicht zwangsläufig, dass Datenträger-I/O oder -Latenz auftritt.
8.2. Hard Faults
Diese erfordern das Lesen von Inhalten aus einem Backing Store auf dem Datenträger. Die Quelle ist nicht auf die Auslagerungsdatei beschränkt.
- Code und Daten einer
.exeoder.dll - Eine speicherabgebildete Datei
- Die Auslagerungsdatei
flowchart TB
accTitle: Die Verzweigung zwischen Soft und Hard Page Faults
accDescr: Beim Zugriff auf eine nicht im Working Set befindliche Seite wird bei nicht erforderlichem Storage-I/O ein Soft Page Fault, bei erforderlichem ein Hard Page Fault behandelt
access["Zugriff auf eine Seite außerhalb des Working Set"] --> storageIo{"Ist Storage-I/O erforderlich"}
storageIo -->|Nein: Standby, gemeinsam genutzt, Demand-Zero usw.| soft["Soft Page Fault"]
soft --> resident["Gelangt ins Working Set, ohne den Datenträger zu lesen"]
storageIo -->|Ja| hard["Hard Page Fault"]
hard --> source{"Woher wird gelesen"}
source --> image["EXE / DLL"]
source --> mapped["Speicherabgebildete Datei"]
source --> pagefile["Auslagerungsdatei"]
image --> loaded["Nach dem Laden ins Working Set"]
mapped --> loaded
pagefile --> loaded
Abbildung 9: Der Name „Page Fault“ allein sagt nichts darüber aus, ob Datenträger-I/O stattgefunden hat.
Microsoft nennt \Memory\Pages/sec, \Memory\Page Reads/sec und \Memory\Pages Input/sec als Zähler zur Messung von Hard Faults. Da hohe Werte hierbei nicht zwangsläufig auf wenig Speicher hindeuten, sollten Sie sie mit Available MBytes, Datenträgerlatenz und der tatsächlichen Antwortzeit korrelieren.6
8.3. Keine pauschale Schwelle festlegen
Ein fester Wert wie „ab 1000 Page Faults/sec liegt eine Anomalie vor“ ändert seine Bedeutung je nach Datenträger, Seitengröße, Workload und Zugriffslokalität.
In der Praxis stellen Sie Folgendes auf derselben Zeitachse nebeneinander.
Memory\Available MBytesMemory\Pages Input/secMemory\Page Reads/sec- Read-Latenz / Queue des betroffenen Datenträgers
- Working Set und Private Bytes des betroffenen Prozesses
- Verarbeitungszeit, Timeouts und UI-Reaktionsfähigkeit der App
Sinkt Available gleichzeitig mit steigender Last, steigen Pages Input/sec und Datenträgerwartezeit, und verschlechtert sich zugleich die Verarbeitungszeit, ist damit die Grundlage gegeben, um durch physischen Speicherdruck verursachtes Paging zu vermuten.
9. Welcher Bildschirm oder welches Werkzeug zeigt was
| Was Sie wissen möchten | Zuerst zu prüfende Kennzahl | Wichtige Werkzeuge |
|---|---|---|
| Wie viel der betrachtete Prozess derzeit im RAM hält | Working Set | Task-Manager, Process Explorer, Get-Process |
| Davon der prozessspezifische Anteil im RAM | Private Working Set / Working Set - Private | Detailspalten des Task-Managers, Process Explorer, PerfMon |
| Die dem betrachteten Prozess eigene Commit-Menge | Private Bytes / Commit Size | Process Explorer, PerfMon, VMMap, Get-Process |
| Der virtuelle Adressbereich des Prozesses | Virtual Bytes / Size | Process Explorer, VMMap, Get-Process |
| Der systemweite Commit-Spielraum | Committed Bytes / Commit Limit | Task-Manager [Leistung], PerfMon |
| Der Wiederverwendungsspielraum des physischen RAM | Available MBytes | Task-Manager, PerfMon |
| Die Aufschlüsselung von Standby, Modified und Dateicache | Seitenlisten-/Verwendungsaufschlüsselung | RAMMap |
| Was innerhalb von Private Bytes gewachsen ist | Heap / Private Data / Managed Heap usw. | VMMap, WinDbg, laufzeitspezifische Dumps |
| Paging mit Datenträgerbeteiligung | Pages Input/sec, Page Reads/sec, Datenträgerlatenz | PerfMon, WPR/WPA |
flowchart TB
accTitle: Ein Werkzeug zur Windows-Speicheruntersuchung wählen
accDescr: Das passende Werkzeug hängt davon ab, ob das Ziel ein einzelner Prozess oder das gesamte System ist, ob ein einzelner Zeitpunkt oder eine Zeitreihe betrachtet wird und ob die Bindung innerhalb einer Laufzeitumgebung nachverfolgt werden muss
question["Was möchten Sie eingrenzen"]
question --> processScope{"Ist das Ziel ein einzelner Prozess"}
processScope -->|Ja| processTime{"Ein einzelner Zeitpunkt oder eine Zeitreihe"}
processTime -->|Aufschlüsselung zu einem Zeitpunkt| vmmap["VMMap"]
processTime -->|Zeitreihe| perfmon["PerfMon / PowerShell"]
processScope -->|Gesamtes System| systemView{"Aufschlüsselung des physischen RAM oder Zeitachse"}
systemView -->|Aufschlüsselung des physischen RAM| rammap["RAMMap"]
systemView -->|Zeitachse einschließlich CPU, I/O und Wartezeiten| wpa["WPR / WPA"]
question --> runtime{"Muss die Bindung innerhalb einer Laufzeitumgebung nachverfolgt werden"}
runtime -->|.NET-Heap| dotnet["dotnet-dump / PerfView"]
runtime -->|Nativer Heap| native["WinDbg / Application Verifier"]
Abbildung 10: Wer zuerst den Umfang und die Zeitachse festlegt, wählt genau das nötige Werkzeug — nicht mehr und nicht weniger.
9.1. Task-Manager
Betrachten Sie im Task-Manager die Bildschirme getrennt.
- [Prozesse] oder [Details]: die Working-Set-Familie und die Commit-Size-Familie einzelner Prozesse
- [Leistung] → [Speicher]: systemweite Werte für In Verwendung, Verfügbar, Committed, Cached, Paged Pool, Non-paged Pool
Urteilen Sie nicht allein anhand der Spalte namens „Speicher“ — klicken Sie mit der rechten Maustaste auf die Spaltenüberschriften der Registerkarte [Details] und fügen Sie die benötigten Spalten hinzu, etwa Working Set, Spitzenwert Working Set und Commit Size. Da sich Spaltennamen je nach Windows-Version und Anzeigesprache unterscheiden können, prüfen Sie die tatsächliche Bedeutung einer Spalte, bevor Sie sie protokollieren.
9.2. Eine Zeitreihe mit PowerShell erfassen
Kennen Sie die ID des betreffenden Prozesses, können Sie mit Get-Process den Verlauf von Working Set, Private Bytes und Virtual Bytes gemeinsam erfassen.
param(
[Parameter(Mandatory)]
[int]$ProcessId,
[int]$IntervalSeconds = 5,
[int]$SampleCount = 60
)
$samples = for ($i = 0; $i -lt $SampleCount; $i++) {
$process = Get-Process -Id $ProcessId -ErrorAction Stop
[pscustomobject]@{
Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
ProcessId = $process.Id
WorkingSetMB = [math]::Round($process.WorkingSet64 / 1MB, 1)
PrivateBytesMB = [math]::Round($process.PrivateMemorySize64 / 1MB, 1)
VirtualBytesMB = [math]::Round($process.VirtualMemorySize64 / 1MB, 1)
Handles = $process.HandleCount
Threads = $process.Threads.Count
}
Start-Sleep -Seconds $IntervalSeconds
}
$samples | Format-Table -AutoSize
$samples | Export-Csv .\memory-samples.csv -NoTypeInformation -Encoding utf8
.NETs Process.WorkingSet64 entspricht Working Set, PrivateMemorySize64 entspricht Private Bytes, und VirtualMemorySize64 entspricht Virtual Bytes.141516
Bei einer App mit mehreren Instanzen verfolgen Sie den Verlauf über die PID statt über den Namen. Bei einer Langzeitüberwachung, bei der ein Neustart die PID ändert, ist ein Aufbau nötig, der Startzeit, Dienstname und Ähnliches protokolliert, damit das Ziel nie verwechselt wird.
9.3. System und Prozess mit PerfMon auf dieselbe Zeitachse bringen
Werden mindestens die folgenden Werte gemeinsam aufgezeichnet, lässt sich leichter eingrenzen.
\Process(<Ziel>)\ID Process
\Process(<Ziel>)\Working Set
\Process(<Ziel>)\Working Set - Private
\Process(<Ziel>)\Private Bytes
\Process(<Ziel>)\Virtual Bytes
\Memory\Available MBytes
\Memory\Committed Bytes
\Memory\Commit Limit
\Memory\Pages Input/sec
\Memory\Page Reads/sec
\Memory\Pool Nonpaged Bytes
\Memory\Pool Paged Bytes
Gibt es mehrere Prozesse mit demselben Namen, oder findet während der Überwachung ein Neustart statt, lässt sich das Ziel allein über den Instanznamen — Process(name) oder Process(name#N) — nicht eindeutig festlegen. Zeichnen Sie bei jeder Probe zusätzlich ID Process auf und übernehmen Sie nur die Instanz, deren Wert mit der verfolgten PID übereinstimmt. Überspannt die Überwachung einen Neustart, der die PID ändert, protokollieren Sie den Zeitpunkt des Wechsels zusätzlich getrennt.
Namen von Windows-Leistungsindikatoren können je nach Anzeigesprache lokalisiert sein. Lässt sich der englische Name in PowerShell nicht direkt angeben, fügen Sie den Zähler über die PerfMon-Oberfläche hinzu, oder prüfen Sie die Namen in Ihrer lokalen Umgebung mit Get-Counter -ListSet *.
9.4. Rollen von VMMap und RAMMap nicht verwechseln
- VMMap: schlüsselt den virtuellen Speicher und das Working Set eines einzelnen Prozesses nach Heap, Image, Mapped File, Private Data, Managed Heap und Ähnlichem auf
- RAMMap: schlüsselt das physische RAM des gesamten Systems nach Verwendungszweck, Seitenliste, Prozess und Datei auf
„Wodurch sind die Private Bytes dieses Prozesses gewachsen“ ist eine Aufgabe für VMMap, „wofür wird das RAM verwendet, das sich aus der Prozessliste nicht erklären lässt“ eine Aufgabe für RAMMap.1713
10. Symptome aus Kombinationen von Werten lesen
| Beobachtetes Muster | Erste Vermutung | Was als Nächstes zu prüfen ist |
|---|---|---|
| Working Set steigt, Private Bytes bleibt stabil | Erster Zugriff auf vorhandene Seiten, gemeinsame DLL, Mapped File, Dateicache | Image / Mapped File in VMMap, Pages Input/sec |
| Private Bytes steigt, Working Set bleibt stabil | Privates Commit ist gewachsen, aber nicht resident oder wurde getrimmt | Heap / Private Data / Managed Heap in VMMap |
| Beides steigt direkt nach dem Start und flacht danach ab | JIT, Cache, Pool, Aufwärmen bei der Initialisierung | Ob es unter derselben zusätzlichen Last erneut steigt |
| Die Untergrenze von Private Bytes steigt mit jeder Lastrunde | Ein Leck, ein unbegrenzter Cache oder ein Allokator, der nach Freigabe Speicher behält | VMMap-Schnappschüsse vor und danach, ein Heap-Dump |
| Nur Working Set fällt plötzlich und kehrt bei Aktivität zurück | Betriebssystem oder App hat das Working Set getrimmt | Private Bytes, Pages Input/sec, Antwortzeit |
| X in Committed X/Y nähert sich Y | Systemweiter Commit-Druck | Größte Verbraucher von Private Bytes, Paged/Nonpaged Pool, Auslagerungsdatei-Einstellungen |
| Available ist niedrig, Pages Input/sec und Datenträgerlatenz sind hoch | Physischer RAM-Druck und Hard Paging | Größte Working-Set-Verbraucher, RAMMap, Korrelation mit der Workload |
| RAM-Nutzung ist hoch, aber es gibt keinen großen Prozess | Cache, gemeinsame Seiten, Kernel-Pools, Treiber, Komprimierung usw. | RAMMap, Pool Nonpaged/Paged Bytes |
| Freies RAM ist vorhanden, aber nur die 32-Bit-App scheitert | Obergrenze des virtuellen Adressraums oder Fragmentierung | Free/Reserved in VMMap, LAA-Einstellung der ausführbaren Datei |
| Private Bytes ist hoch, wächst aber bei wiederholter Verarbeitung nicht weiter | Möglicherweise ein Pool oder Cache, der einen Höchststand hält | Seine Obergrenze, Wiederverwendungsverhalten, Stabilität nach dem Höchststand |
Das Wichtigste an dieser Tabelle ist, sie in Kombination und nicht anhand eines einzelnen Werts zu lesen.
11. Praktisches Vorgehen bei der Untersuchung eines Speicherlecks
11.1. Zunächst Reproduktionsbedingungen und stationären Punkt festlegen
„Es wächst über mehrere Tage“ allein lässt sich nicht vergleichen.
- Wie viel vom Aufwärmen nach dem Start einbezogen wird
- Woraus ein Zyklus der Bedienung besteht
- Wie viele Sekunden nach einem Zyklus gewartet wird
- Wie viele Runden bis zur Cache-Obergrenze nötig sind
- Ob dieselbe Eingabe für die fehlerfreie und die fehlerhafte Version verwendet werden kann
Legen Sie all dies fest.
11.2. Prozess und System gleichzeitig aufzeichnen
Protokollieren Sie mindestens die folgenden Werte zu denselben Zeitpunkten.
- Working Set des Ziels
- Private Bytes des Ziels
- Virtual Bytes des Ziels
- Committed Bytes / Commit Limit des Systems
- Available MBytes
- Pages Input/sec
- Anzahl der Handles, Anzahl der Threads
- Anzahl der Vorgänge oder verarbeiteten Elemente
Bleiben die Private Bytes des Prozesses stabil, während allein der Commit des Systems weiter wächst, müssen Sie den Blick auf andere Prozesse, den Kernel, Treiber und gemeinsame Sections erweitern.
11.3. Zuerst festlegen, welche „Dimension“ wächst
- Nur Working Set: residente Seiten, gemeinsam genutzt oder dateibasiert, Trim und Neuladen
- Private Bytes: prozessspezifisches Commit
- Nur Virtual Bytes: Reserve, Mapping, Fragmentierung des Adressraums
- Nur System Commit: einschließlich anderer Prozesse und der Kernel-Seite
- Nonpaged Pool: Treiber-/Kernel-Seite
- Handles / GDI / USER: Lecks bei anderen Ressourcen als Speicher
Überspringen Sie diese Reihenfolge und erstellen Sie sofort einen Dump, landen Sie dabei, eine Menge Informationen über das falsche Ziel zu lesen.
11.4. Zur Aufschlüsselung übergehen
- Nativer Prozess: VMMap, WinDbg, Application Verifier, Heap-Tracing
- .NET:
dotnet-counters,dotnet-gcdump,dotnet-dump, PerfView - Systemweit: RAMMap, PerfMon, WPR/WPA
- Kernel-Pool: PoolMon, WinDbg
VMMap zeigt den committeten virtuellen Speicher eines Prozesses und das jeweils dafür zugewiesene Working Set nach Typ aufgeschlüsselt an. Wie weit sich das Wachstum bei Private Bytes auf „Heap“, „Private Data“, „Managed Heap“ oder „Mapped File“ eingrenzen lässt, macht für die weiteren Untersuchungskosten einen erheblichen Unterschied.17
11.5. Nach der Korrektur den Verlauf unter denselben Bedingungen vergleichen
Es genügt nicht, dass sich der Spitzenwert vor und nach der Korrektur unterscheidet. Unterscheidet sich der Ausgangswert, kann sich der Vergleich leicht umkehren.
- Derselbe Startzustand
- Dieselbe Eingabe
- Dieselbe Anzahl von Vorgängen
- Dieselbe Wartezeit
- Dasselbe Abtastintervall
— und vergleichen Sie danach den Untergrenzwert und den Verlauf nach jedem Zyklus. Der Nachweis einer Leck-Korrektur besteht nicht darin, dass „der Höchstwert kleiner wurde“, sondern darin, dass das Wachstum auch bei wiederholt gleicher Last konvergiert.
12. Häufige Missverständnisse anders formuliert
Missverständnis 1: Der Speicherwert im Task-Manager entspricht der von der App insgesamt zugewiesenen Menge
Anders formuliert: Prüfen Sie, um welche Spalte es sich handelt. Bei der Working-Set-Familie ist es die derzeit im RAM residente Menge, bei der Commit-Size-Familie die diesem Prozess eigene Commit-Menge.
Missverständnis 2: Private Bytes entspricht der Byte-Zahl auf der Auslagerungsdatei
Anders formuliert: Private Bytes ist die private Commit Charge. Es ist eine logisch versprochene Menge, die sowohl Seiten im RAM als auch Seiten umfasst, die bei Bedarf durch die Auslagerungsdatei abgesichert würden.
Missverständnis 3: Commit X/Y entspricht der Nutzung der Auslagerungsdatei / der Kapazität der Auslagerungsdatei
Anders formuliert: X ist die systemweite Commit Charge, Y das Commit Limit. Die Auslagerungsdatei erweitert Y, aber X übersetzt sich nicht unmittelbar in tatsächliche Nutzung auf dem Datenträger.
Missverständnis 4: Ein hoher Wert bei Page Faults/sec bedeutet, dass auf den Datenträger ausgelagert wird
Anders formuliert: Darin sind auch Soft Faults enthalten. Prüfen Sie Pages Input/sec, Page Reads/sec und die Datenträgerlatenz, um festzustellen, ob tatsächlich Datenträger-I/O beteiligt ist.
Missverständnis 5: Wenig freier RAM bedeutet Speichermangel
Anders formuliert: Betrachten Sie Available, Standby, Hard Paging und Antwortzeit. Dass wiederverwendbarer Cache das RAM füllt, ist normal.
Missverständnis 6: Ein verkleinertes Working Set bedeutet, dass ein Speicherleck behoben wurde
Anders formuliert: Möglicherweise wurden lediglich Seiten aus dem RAM verdrängt. Prüfen Sie, ob Private Bytes und die im Heap gehaltenen Referenzen tatsächlich zurückgegangen sind.
Missverständnis 7: Ein Anstieg bei Private Bytes bestätigt ein Leck
Anders formuliert: Das lässt sich erst beurteilen, nachdem Sie geprüft haben, ob es bei Wiederholung derselben Workload konvergiert, welche Art von Speicher gewachsen ist und ob es sich um einen freigebbaren Cache handelt.
13. Zusammenfassung
- Windows’ „Speicherauslastung“ ist keine einzelne Zahl. Denken Sie Adressraum, Commit, RAM-Residenz und Teilbarkeit getrennt.
- Working Set sind die derzeit im RAM liegenden Seiten, einschließlich sowohl privater als auch gemeinsamer. Private Working Set sind darunter die prozessspezifischen residenten Seiten.
- Private Bytes ist die prozessspezifische Commit Charge; sie ist weder die derzeit im RAM liegende Menge noch die tatsächlich in die Auslagerungsdatei geschriebene Menge.
- Committed X/Y ist die systemweite Commit Charge / das Commit Limit. Die Auslagerungsdatei stützt vor allem das Commit Limit, das Auslagern geänderter Seiten und Absturzabbilder.
- Eine reservierte virtuelle Adresse, eine committete Seite und eine Seite, die tatsächlich berührt wurde und ins Working Set gelangt ist, sind getrennte Stufen.
- Ein Page Fault ist normaler Betrieb, und ein Soft Fault liest nicht von der Festplatte. Auch Hard Faults können nicht nur aus der Auslagerungsdatei, sondern auch aus einer EXE, DLL oder Mapped File entstehen.
- Ein Speicherleck wird nicht anhand der Größe zu einem einzelnen Zeitpunkt bewiesen, sondern anhand des Untergrenzwerts und Verlaufs nach derselben Last, zusammen mit der Aufschlüsselung.
- Grundsätzlich gilt: VMMap für die Aufschlüsselung eines einzelnen Prozesses, RAMMap für das physische RAM des gesamten Systems, PerfMon für eine Zeitreihe, und ein spezialisiertes Dump-Werkzeug für das, was innerhalb einer Laufzeitumgebung geschieht.
Bemerken Sie das nächste Mal im Task-Manager, dass „der Speicher wächst“, stellen Sie sich zunächst diese Frage.
Wächst das Working Set, Private Bytes, Virtual Bytes oder der System Commit?
Allein diese Frage macht den Einstiegspunkt Ihrer Untersuchung erheblich präziser.
Verwandte Artikel
- GC-Wartezeit von einem Speicherleck in .NET unterscheiden — Praktisches Vorgehen, um wachsenden Speicher zu beobachten, zu vergleichen und zu beweisen
- Process Explorer / Handle / VMMap in der Praxis — Hängern, Lecks und „Datei wird verwendet“ vom aktuellen Zustand aus auf den Grund gehen
- Fallstricke bei Shared Memory und Best Practices für die Praxis
- Die Tiefen von Windows-I/O (Teil 4) — Cache-Manager: Wann erreicht Ihr WriteFile tatsächlich die Festplatte?
- Untersuchung eines Absturzes einer Industriekamera-Anwendung nach Langzeitbetrieb - Der Handle-Leak (Teil 1)
Verwandte Beratungsleistungen
Die KomuraSoft LLC übernimmt Ursachenuntersuchungen zu wachsendem Speicherverbrauch von Windows-Anwendungen, Leistungseinbußen nach Langzeitbetrieb, OutOfMemory in 32-Bit-Prozessen sowie Speicherengpässen, die nur in der Umgebung eines Kunden auftreten, unter Einsatz von PerfMon, VMMap, RAMMap, WinDbg und .NET-Diagnosewerkzeugen. Wir belassen es nicht bei „der Speicher ist hoch“, sondern grenzen ein, welcher Bereich durch welche Operation warum wächst und von wo aus er referenziert oder gehalten wird.
- Windows-Anwendungsentwicklung
- Fehleruntersuchung und Ursachenanalyse
- Technische Beratung und Design-Review
- Kontakt
Referenzlinks
-
Microsoft Learn, Working Set. Dazu, dass das Working Set eines Prozesses die Menge der derzeit im physischen Speicher residenten Seiten ist, einschließlich gemeinsam nutzbarer Seiten; zum Unterschied zwischen Soft und Hard Page Faults; zu Transition-Seiten; sowie zum Entfernen von Seiten aus dem Working Set. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, PROCESS_MEMORY_COUNTERS_EX2 structure. Zu den Definitionen von WorkingSetSize, PrivateWorkingSetSize, PrivateUsage und SharedCommitUsage sowie dazu, dass PagefileUsage und PrivateUsage beide die Commit Charge des Prozesses darstellen. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Introduction to page files. Dazu, dass die Auslagerungsdatei das Auslagern geänderter Seiten, Systemabsturzabbilder und die Erweiterung des System Commit Limit stützt; zu den Definitionen von System Commit Charge und Commit Limit; sowie zur Messung über Task-Manager und Leistungsindikatoren. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Page State. Zu den Zuständen Free, Reserved und Committed einer virtuellen Seite sowie dazu, dass Reserved-Seiten kein zugeordnetes physisches Speicherobjekt besitzen und nicht zugänglich sind. ↩ ↩2
-
Microsoft Learn, VirtualAlloc function. Zum Unterschied zwischen MEM_RESERVE und MEM_COMMIT; dazu, dass das Committen gegen den Gesamtspeicher und die Auslagerungsdatei des Systems angerechnet wird; sowie dazu, dass die tatsächliche physische Seite unter Umständen erst beim ersten Zugriff zugewiesen wird. ↩ ↩2 ↩3
-
Microsoft Learn, How to determine the appropriate page file size for 64-bit versions of Windows. Dazu, dass die Größe der Auslagerungsdatei von der Spitzen-Commit-Charge und den Anforderungen an Absturzabbilder abhängt; dazu, dass Hard Page Faults nicht nur von der Auslagerungsdatei, sondern auch von EXE-, DLL- und speicherabgebildeten Dateien lesen; sowie zu den zugehörigen Leistungsindikatoren. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Virtual Address Space. Dazu, dass jeder Prozess einen eigenen, unabhängigen virtuellen Adressraum und eine eigene Seitentabelle besitzt und eine virtuelle Adresse keine physische Adresse selbst ist. ↩
-
Microsoft Learn, Memory Limits for Windows and Windows Server Releases. Dazu, dass der virtuelle Adressraum eines 32-Bit-Prozesses im Benutzermodus normalerweise 2GB beträgt und unter 64-Bit-Windows je nach IMAGE_FILE_LARGE_ADDRESS_AWARE entweder 2GB oder 4GB wird. ↩
-
Microsoft Learn, SetProcessWorkingSetSize function. Dazu, dass der minimale und maximale Wert des Working Set keine Residenz garantieren; dazu, dass sich ein Working Set leeren lässt; sowie dazu, dass übermäßige Einstellungen oder Operationen die Systemleistung verschlechtern können. ↩
-
Microsoft Learn, Memory Performance Information. Zum Zusammenhang zwischen Windows-Leistungsindikatoren, Speicherverwaltungs-APIs und der Anzeige im Task-Manager, einschließlich Working Set, Working Set - Private und Private Bytes des Process-Objekts sowie Committed Bytes und Commit Limit des System-Objekts. ↩
-
Microsoft Learn, MapViewOfFile function. Dazu, dass bei
FILE_MAP_COPYjede Seite potenziell Copy-on-write werden kann, weshalb die Commit Charge für die gesamte View bereits beim Mappen reserviert wird, um sie über die Auslagerungsdatei absichern zu können. ↩ -
Microsoft Learn, Understanding Node Metrics and Properties in HPC Cluster Manager. Dazu, dass Available Physical Memory als Summe der Listen Zeroed, Free und Standby berechnet wird, sowie zur Bedeutung der einzelnen Seitenlisten. ↩
-
Microsoft Sysinternals, RAMMap. Zur Analyse der Nutzung des physischen Windows-Speichers nach Verwendungszweck, Seitenliste, Prozess, Priorität, physischer Seite und Datei. ↩ ↩2
-
Microsoft Learn, Process.WorkingSet64 Property. Dazu, dass
WorkingSet64das Working Set des Prozesses in Bytes zurückgibt und dem Working-Set-Leistungsindikator des Process-Objekts entspricht. ↩ -
Microsoft Learn, Process.PrivateMemorySize64 Property. Dazu, dass
PrivateMemorySize64den nicht mit anderen Prozessen teilbaren, prozesseigenen Speicher zurückgibt und dem Private-Bytes-Leistungsindikator entspricht. ↩ -
Microsoft Learn, Process.VirtualMemorySize64 Property. Dazu, dass
VirtualMemorySize64die Menge des dem Prozess zugewiesenen virtuellen Speichers zurückgibt und dem Virtual-Bytes-Leistungsindikator entspricht. ↩ -
Microsoft Sysinternals, VMMap. Zur Aufschlüsselung des committeten virtuellen Speichers eines Prozesses nach Typ, zur Anzeige des jeweils zugewiesenen physischen Speichers (Working Set) sowie zu einer detaillierten Speicherzuordnung. ↩ ↩2
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
WMI/CIM aus C# und PowerShell verwenden — Praxisleitfaden für Hardwareinformationen, Prozessüberwachung und Remoteabfragen
WMI/CIM ist die Standardlösung, um die Seriennummer eines PCs auszulesen, freien Festplattenspeicher zu überwachen und den Start von Proz...
Die Tiefen von Windows I/O (Teil 6, Finale) ── Filtertreiber und Minifilter: Warum Procmon und Virenscanner sich in die I/O einklinken können
Der Abschluss einer bebilderten Artikelserie über Windows-Filtertreiber und Minifilter. Er behandelt den Filter-Manager und Altitudes, Pr...
Process Explorer / Handle / VMMap in der Praxis — Hängern, Lecks und „Datei wird verwendet“ vom aktuellen Zustand aus nachjagen
Teil zwei unserer praxisnahen Sysinternals-Serie, zu „es wird immer langsamer“, „die Datei lässt sich nicht löschen“ und „es hängt“. Wir ...
Registry-32-Bit/64-Bit-Umleitung und Virtualisierungsfallen — Wow6432Node und das Problem „Der Wert, den ich geschrieben habe, ist nicht da“
Wie die Schreibvorgänge einer 32-Bit-App nach HKLM\Software zu Wow6432Node umgeleitet werden, unter welchen Bedingungen die UAC-Virtualis...
Incident Response endet nicht mit der Wiederherstellung ── Eine Postmortem-Vorlage (Rückfallprävention) für kleine Entwicklungsteams
Einen Vorfall als erledigt zu betrachten, sobald er behoben und man sich entschuldigt hat, garantiert, dass er sich wiederholt. Dieser Ar...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Windows-App-Entwicklung
Geschäftsanwendungen, Geräteintegration und Kommunikationstools von den Anforderungen bis zur Umsetzung.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Zeigt die Spalte „Speicher“ im Task-Manager den gesamten von einer App belegten Speicher?
- Nein. Der Task-Manager hat mehrere Speicherspalten — die Working-Set-Familie, die Private-Working-Set-Familie, Commit Size und weitere —, und die Bedeutung hängt davon ab, welchen Bildschirm und welche Spalte Sie betrachten. Working Set sind die Seiten, die derzeit im RAM liegen; Private Bytes oder Commit Size ist die für diesen Prozess spezifische Commit-Menge. Lesen Sie eine einzelne Spalte „Speicher“ nicht als die gesamte von einer App belegte Kapazität oder als Größe eines Lecks.
- Was ist der Unterschied zwischen Working Set und Private Bytes?
- Working Set ist die Menge der für den Prozess sichtbaren Seiten, die derzeit im physischen RAM resident sind, einschließlich gemeinsam nutzbarer Seiten wie DLL-Code oder speicherabgebildeter Dateien. Private Bytes ist die Menge des ausschließlich von diesem Prozess genutzten committeten Speichers, unabhängig davon, ob er derzeit im RAM resident ist. Beide sind daher nie gleich groß, und keiner der beiden Werte ist durchgängig größer als der andere.
- Bedeutet „Committed 18/32GB“ im Task-Manager, dass 18GB in die Auslagerungsdatei geschrieben wurden?
- Nein. Der linke Wert ist die Commit-Menge, die das gesamte System derzeit zu unterstützen verspricht, der rechte Wert ist die Commit-Obergrenze, die das System stützen kann. Die Obergrenze ergibt sich grob aus RAM plus Auslagerungsdatei, aber nicht die gesamte linke Summe liegt tatsächlich in der Auslagerungsdatei. Die meisten committeten Seiten liegen im RAM, und manchen committeten Seiten wurde noch nie eine physische Seite zugewiesen. Seiten dagegen, die aus ihrer Ursprungsdatei neu geladen werden können — etwa EXE-, DLL- und speicherabgebildete Dateien —, erhöhen das Working Set nicht zwangsläufig um denselben Betrag wie das private Commit.
- Kann OutOfMemory auftreten, obwohl freier RAM verfügbar ist?
- Ja. Eine Zuweisung kann aus anderen Gründen als physischem RAM-Mangel fehlschlagen, etwa weil ein 32-Bit-Prozess seinen virtuellen Adressraum erschöpft hat, kein zusammenhängender freier Adressbereich in ausreichender Größe existiert, die System-Commit-Obergrenze erreicht ist oder ein Job-Objekt beziehungsweise die Laufzeitumgebung eine eigene Grenze hat. Insbesondere ein 32-Bit-Prozess unter 64-Bit-Windows ist ohne Large Address Awareness normalerweise auf 2GB virtuellen Adressraum im Benutzermodus begrenzt.
- Wird Windows schneller, wenn die Auslagerungsdatei deaktiviert wird?
- Im Allgemeinen lässt sich das nicht pauschal bejahen. Das Deaktivieren der Auslagerungsdatei senkt die Commit-Obergrenze des Systems, erschwert das Auslagern ungenutzter geänderter Seiten aus dem RAM und wirkt sich auch auf die Konfiguration von Absturzabbildern aus. Die Größe der Auslagerungsdatei sollte anhand der Spitzen-Commit-Menge und des benötigten Absturzabbilds festgelegt werden — sie ist keine Einstellung, die man ohne Grund deaktiviert.
- Bedeutet ein hoher Wert bei Page Faults/sec einen Speichermangel?
- Das lässt sich daraus allein nicht entscheiden. Bei Page Faults gibt es Soft Faults, die sich über Standby-Seiten im RAM oder mit einem anderen Prozess gemeinsam genutzte Seiten auflösen lassen, und Hard Faults, die von der Festplatte lesen. Betrachten Sie nicht Page Faults/sec allein, sondern prüfen Sie Pages Input/sec, Page Reads/sec, Available MBytes, die Datenträgerlatenz und die Verarbeitungszeit gemeinsam auf derselben Zeitachse.
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.