Les profondeurs de la mémoire Windows (partie 1) — L'instant où une adresse virtuelle devient de la RAM physique : un défaut de page de bout en bout
· Go Komura · Windows, Gestion de la mémoire, VirtualAlloc, Défaut de page, VAD, Supervision des performances
Passer MEM_COMMIT à VirtualAlloc augmente le Commit à cet instant. Le Working Set, en revanche, n’augmente pas nécessairement du même montant. Alors, où est la mémoire que vous pensiez avoir allouée ?
La réponse est que la plupart des pages n’ont pas encore de RAM physique correspondante. Windows retarde l’attribution d’une page physique jusqu’à ce que l’application touche réellement la page. Quand le premier accès fait lever un défaut de page au processeur, le gestionnaire de mémoire examine le VAD, la PTE, les attributs de protection et le magasin de soutien, et lie la RAM une page à la fois si besoin.1
Cet article suit le chemin que « le premier octet que vous touchez » parcourt jusqu’à la RAM physique. Si vous voulez d’abord clarifier le sens de chiffres comme Working Set et Commit, voyez l’article d’introduction « Que représente réellement la « mémoire utilisée » sous Windows ── Bien lire Working Set, Private Bytes, Commit et le fichier d’échange ». Cette série ne redéfinit pas les termes utilisés là ; elle creuse, côté mécanisme, « pourquoi le chiffre sort comme ça ».
« Les profondeurs de la mémoire Windows » — les 3 parties
- Partie 1 (cet article) : adresses virtuelles et défauts de page
Nous suivons quand une région allouée avecVirtualAllocobtient de la RAM physique. - Partie 2 : la vie d’une page physique
Nous suivons comment une page qui quitte le Working Set circule entre Modified, Standby, Free et Zeroed. - Partie 3 : objets section et copie à l’écriture
Nous suivons pourquoi les DLL, les mappages de fichiers et la mémoire partagée peuvent partager des pages physiques.
La question à laquelle répond la partie 1 n’est qu’une.
À quel instant une adresse virtuelle déjà en Commit devient-elle de la RAM physique ?
Le public visé est celui des développeurs et des exploitants qui veulent comprendre, depuis le mécanisme, l’usage mémoire des applications Windows, les défauts de page juste après le démarrage, 0xC0000005, et les chiffres de VMMap et PerfMon. Les prérequis sont Windows 10/11 ou une version actuelle de Windows Server, et le bagage requis est les pointeurs et les bases de VirtualAlloc ; l’expérience des dispositions de bits des tables de pages ou d’un débogueur noyau n’est pas nécessaire. La difficulté est intermédiaire. Nous utilisons les noms de structures internes, mais nous n’assumons pas de dispositions non documentées qui dépendent d’une compilation Windows particulière.
1. La conclusion d’abord
Le flux ordinaire de la mémoire privée, en une ligne, est celui-ci.
Reserve met de côté une plage d’adresses virtuelles, Commit impute une charge de commit pour garantir un lieu futur où conserver le contenu, et le défaut de page du premier accès attribue la page physique.
Autrement dit, MEM_COMMIT n’est pas un ordre qui dit « alloue de la RAM tout de suite ». La documentation Microsoft de VirtualAlloc garantit aussi que le contenu initial d’une page en Commit est zéro, tout en expliquant que la page physique réelle n’est pas attribuée tant que l’adresse virtuelle n’est pas accédée.1
Cela dit, il est aussi inexact de prétendre que « Reserve/Commit n’écrivent que dans le VAD ». En pratique, Reserve crée surtout un VAD qui représente la plage d’adresses virtuelles et ses attributs, et Commit augmente le Commit Total du système et enregistre l’état commité de la plage. Les niveaux intermédiaires de table de pages et les PTE individuelles sont construits paresseusement au besoin, et la liaison finale à la RAM physique se produit normalement au premier accès.
Le Commit n’est pas une promesse vide ; c’est une promesse à l’échelle du système que le contenu pourra être conservé à l’avenir en RAM ou dans un magasin de soutien approprié. Le point d’entrée qui matérialise cette promesse une page à la fois est le défaut de page.
flowchart TB
accTitle: Ce qui se passe à Reserve, Commit et au premier accès
accDescr: MEM_RESERVE enregistre la plage et les attributs dans le VAD, MEM_COMMIT consomme le Commit Total pour promettre le stockage, et le défaut de page du premier accès attribue une page physique et l'ajoute au Working Set
reserve["1. MEM_RESERVE"] --> commit["2. MEM_COMMIT"]
commit --> touch["3. Premier accès(Touch)"]
reserve -.-> vad["Enregistrer la plage et les attributs dans le VAD"]
commit -.-> charge["Consommer le Commit Total(pas encore de page physique)"]
touch --> fault["Défaut de page"]
fault --> zero["Lier une page physique mise à zéro à la PTE"]
zero --> ws["L'ajouter au Working Set et réexécuter l'instruction"]
Figure 1 : Reserve, Commit et Touch sont des événements séparés. La RAM physique n’est liée qu’à la dernière étape, le premier accès.
2. Trois registres qui suivent une page virtuelle
Pour comprendre le chemin d’une adresse virtuelle vers la RAM physique, il faut distinguer les trois sortes de registres que Windows tient.
| Registre | Unité | Rôle |
|---|---|---|
| VAD | Plage d’adresses virtuelles | Gère ce qu’est la région, Reserve/Commit, la protection et la correspondance de section |
| Table de pages / PTE | Page virtuelle | Représente la traduction actuelle vers une page physique, ou un état non réalisé |
| Base PFN | Page physique | Suit la propriété, les références et l’état de chaque page de RAM |
Le VAD tient des informations sur une plage, la PTE sur une page virtuelle, et la base PFN sur une page physique. Le gestionnaire de défaut de page croise ces registres pour décider si l’accès peut continuer.
flowchart TB
accTitle: Trois registres d'une adresse virtuelle à la RAM physique
accDescr: Une adresse virtuelle est gérée par le VAD à la granularité de plage et par la PTE à la granularité de page virtuelle, et la base PFN suit la page physique cible de la traduction de la PTE à la granularité de page physique
va["Adresse virtuelle"] --> vad["VAD(registre de plage)"]
va --> pte["PTE(registre de page virtuelle)"]
vad -.->|Juger Reserve/Commit et protection| pte
pte -->|Traduction valide| pfn["Base PFN(registre de page physique)"]
pfn --> ram["Page de RAM physique"]
Figure 2 : Trois registres à des granularités différentes. Le traitement du défaut croise le VAD et la PTE, puis répercute le résultat côté PFN.
Les vedettes de cet article sont le VAD et la PTE. Nous regarderons la base PFN du côté page physique dans la partie 2.
3. Reserve, Commit et Touch sont des événements séparés
3.1. Reserve — revendiquer une adresse
D’abord, réservez une plage contiguë de 256 MiB d’adresses virtuelles.
void* base = VirtualAlloc(
nullptr,
256ull * 1024 * 1024,
MEM_RESERVE,
PAGE_NOACCESS);
Ce qui s’est passé à ce point, c’est seulement qu’une adresse a été mise de côté dans l’espace virtuel du processus pour que d’autres allocations ne puissent pas utiliser cette plage. MEM_RESERVE n’attribue aucun stockage physique en RAM ni dans le fichier d’échange.1
Parce qu’un processus 64 bits a un vaste espace virtuel, il devient pratique de Reserve d’abord une grande plage et de Commit seulement les parties dont vous avez besoin plus tard.
3.2. Commit — promettre que cela pourra être conservé
Ensuite, Committez la plage réservée.
void* committed = VirtualAlloc(
base,
256ull * 1024 * 1024,
MEM_COMMIT,
PAGE_READWRITE);
En cas de succès, le montant promis qui se reflète dans le Commit Total du système — et habituellement dans les Private Bytes du processus — augmente. Même ainsi, 256 MiB de pages physiques ne se mettent pas en rang d’un coup. Les pages ordinaires restent physiquement non attribuées jusqu’au premier accès.12
Alors, à quoi sert le Commit ? C’est que quand le système ne peut pas prendre la promesse, il peut renvoyer un échec au moment du Commit, plutôt qu’au milieu de l’utilisation de la mémoire.
3.3. Touch — quand une page physique devient nécessaire
Enfin, l’affectation suivante écrit pour la première fois dans la première page.
static_cast<unsigned char*>(base)[0] = 1;
Le processeur essaie de traduire l’adresse virtuelle en adresse physique, mais la PTE n’a pas encore de traduction valide vers une page physique. Un défaut de page se produit ici.
Le gestionnaire de mémoire qui reçoit le contrôle juge qu’il s’agit « d’un premier accès à une page privée commise et inscriptible », obtient une page physique mise à zéro, la lie à la PTE et l’ajoute au Working Set. Il réexécute ensuite l’instruction d’écriture qui a échoué.
Du point de vue de l’application, cela ressemble à une simple affectation, mais en interne le contrôle entre dans le noyau au milieu de l’affectation, une page physique est attribuée, et l’exécution revient à la même instruction.
4. Le VAD — le registre de plages de l’espace virtuel
VAD signifie Virtual Address Descriptor, et Windows gère les plages d’adresses en usage d’un processus comme un arbre de VAD. Avec la commande !vad de WinDbg, vous pouvez inspecter les VPN de début et de fin, le Commit, les attributs de protection, Private/Mapped, la Control Area, et plus.3
Les informations représentatives qu’un VAD enregistre incluent les suivantes.
- Début et fin de la plage d’adresses
- Nature, comme Private, Mapped ou Image
- État Reserve/Commit
- Protection telle que lecture, écriture, exécution et copie à l’écriture
- Correspondance à un fichier ou une section
- Attributs spéciaux tels que les pages de garde
La raison de gérer par plage est l’efficacité. 256 MiB, c’est 65 536 pages à 4 KiB. Plutôt que de construire d’emblée une structure de gestion complète pour chaque page, il est moins gaspilleur de tenir « cette plage contiguë est une réservation » dans un VAD et de matérialiser les pages au fur et à mesure.
4.1. Trouver un VAD ne garantit pas la récupération
« S’il est dans un VAD, le défaut est résolu ; sinon, vous avez une violation d’accès » est une explication d’entrée de gamme commode, mais elle simplifie trop. Même quand un VAD est trouvé, l’accès ordinaire ne peut pas continuer dans des cas tels que les suivants.
- Reserve seulement, et la page cible n’est pas commise
PAGE_NOACCESS- Une écriture vers une page en lecture seule
- L’exécution d’une instruction depuis une page non exécutable
- Premier contact d’une page de garde
- Un contact hors de la plage valide d’une section
Inversement, même si la PTE est invalide, si l’état logiciel du VAD et de la PTE montre un accès légitime, cela peut se résoudre en demand-zero, restauration Transition, page-in ou CoW. Plus précisément, la réponse est juger ensemble VAD, PTE, attributs de protection et type d’accès.
5. Tables de pages et TLB
Le pointeur qu’une application tient est une adresse virtuelle. Pour que le processeur accède à la RAM, il doit traduire un numéro de page virtuelle en numéro de page physique. Cette table de traduction hiérarchique est la table de pages, et l’entrée feuille est la PTE (Page Table Entry).
Une PTE valide tient conceptuellement un PFN, une protection lecture/écriture/exécution, une permission en mode utilisateur, Accessed/Dirty, et des informations similaires. La disposition réelle des bits dépend du processeur et de la version de Windows.
Parcourir la table de pages à chaque fois serait beaucoup trop lent, donc le processeur met en cache les traductions récentes dans le TLB (Translation Lookaside Buffer). La traduction d’adresse se déroule dans cet ordre.
- Si le TLB a une traduction et que l’accès correspond à cette protection, ce résultat est utilisé.
- Si le TLB n’a pas de traduction, le processeur parcourt la table de pages.
- S’il y a une PTE valide et que la protection correspond aussi, elle est enregistrée dans le TLB et l’exécution continue.
- S’il n’y a pas de traduction valide, ou s’il y a une violation de protection, le contrôle passe au point d’entrée du défaut de page. La vérification de protection est aussi effectuée quand la traduction venait du TLB.
Comme le montre ce flux, un échec TLB et un défaut de page sont des choses différentes. Si le seul problème est que le TLB n’a pas de traduction et que la PTE est valide, il ne se produit qu’un parcours de table de pages. Inversement, même si le TLB a une traduction, une violation de protection telle qu’une écriture vers une page en lecture seule ou l’exécution d’une instruction sur une page non exécutable passe au point d’entrée du défaut de page. C’est pourquoi une écriture vers une page CoW peut fauter même quand la traduction est déjà en cache.
flowchart TB
accTitle: Flux de traduction d'adresse et point d'entrée du défaut de page
accDescr: Même si le TLB a une traduction, un écart de protection passe au point d'entrée du défaut de page. Si le TLB n'a pas de traduction, la table de pages est parcourue ; une PTE valide qui correspond aussi à la protection est enregistrée dans le TLB et l'exécution continue, et une traduction invalide ou une violation de protection passe au point d'entrée du défaut de page
access["Accès mémoire"] --> tlb{"Le TLB a-t-il une traduction ?"}
tlb -->|Oui| perm{"L'accès correspond-il à la protection ?"}
perm -->|Correspond| go["Continuer avec cette traduction"]
perm -->|Violation de protection| entry["Vers le point d'entrée du défaut de page"]
tlb -->|Non| walk["Parcours de table de pages"]
walk --> valid{"PTE valide et protection aussi correspondante ?"}
valid -->|Oui| register["Enregistrer dans le TLB et continuer(pas de défaut)"]
valid -->|Invalide ou violation de protection| entry
Figure 3 : Un échec TLB peut se résoudre par un parcours de table de pages. Le contrôle passe à un défaut de page quand la traduction est invalide ou qu’il y a une violation de protection, et une violation de protection se produit même sur un succès TLB.
5.1. Une PTE invalide n’est pas simplement un blanc
Même une PTE invalide n’est pas vide. À partir de l’état logiciel d’une PTE invalide, Windows distingue des cas tels que les suivants.
- Une page demand-zero qui n’a jamais été matérialisée
- Une page Transition qui reste en RAM
- Une page partagée qui se réfère à une Prototype PTE
- Une page privée sauvegardée dans le fichier d’échange
- Une violation de protection ou une région invalide
Le travail du processeur est seulement de décider « ce n’est pas une traduction valide ordinaire » et de la remettre au noyau ; le gestionnaire de mémoire fournit le sens à partir de là.
6. Un défaut de page de bout en bout
Suivons une première écriture vers une page privée commise en six étapes.
- Le processeur essaie d’écrire.
Il vérifie le TLB et la table de pages, mais la PTE cible n’a pas de PFN valide. - Le processeur lève un défaut de page.
Il passe l’adresse virtuelle fautive, le type lecture/écriture/exécution, utilisateur/noyau, et si le problème est une traduction manquante ou une violation de protection au noyau. - Le gestionnaire de mémoire examine le VAD et la PTE.
Il décide si la page est commise, si la protection correspond, et lequel de demand-zero, Transition, partagé, page-in, CoW ou une exception s’applique. - S’il s’agit de demand-zero, une page physique mise à zéro est obtenue.
Une page nouvellement remise doit être à zéro pour qu’aucune donnée d’un autre processus ne fuie. - Les informations de gestion PTE et PFN sont mises à jour.
Le PFN et la protection sont posés dans la PTE, la page physique est rendue Active, et elle est ajoutée au Working Set du processus. - L’instruction qui a échoué est réexécutée.
Parce que le défaut s’est résolu normalement, aucune exception en mode utilisateur n’est livrée, et l’application continue l’affectation comme d’habitude.
Les événements ETW de défaut de page enregistrent aussi Transition, Demand Zero, Copy-on-Write, Guard Page, Hard Page Fault et Access Violation comme des sortes distinctes.4
Un défaut de page n’est donc pas un mot qui signifie « anormal » dès le départ. C’est le point d’entrée commun pour demander à l’OS de décider quand le processeur n’a pas pu traduire sur le chemin ordinaire.
flowchart LR
accTitle: Branchement des résolutions de défaut de page
accDescr: Le gestionnaire de mémoire juge le VAD, la PTE, les attributs de protection et le type d'accès, et dispatch vers demand-zero, la reconnexion d'une page encore en RAM, un défaut dur depuis un magasin de soutien, la copie à l'écriture, une notification de page de garde, ou une exception
faultIn["Un défaut de page se produit"] --> judge["Juger VAD, PTE, protection, type"]
judge -->|Premier accès| dz["Demand-zero(souple)"]
judge -->|Encore en RAM| soft["Reconnecter depuis Standby(souple)"]
judge -->|Lecture disque requise| hard["Défaut dur(E/S disque)"]
judge -->|Écriture CoW| cow["Copier et échanger la PTE"]
judge -->|Page de garde| guard["Effacer la garde et notifier"]
judge -->|Irrésolvable| av["Exception(0xC0000005 etc.)"]
Figure 4 : Les défauts qui entrent par le même point d’entrée se séparent en six sortes de résultats selon le jugement. Les détails des pages de garde sont traités à la section 9.
7. Demand-zero — un défaut souple qui ne lit pas le disque
Le demand-zero est le défaut souple représentatif qui se produit quand une page privée commise est touchée pour la première fois. La documentation Working Set de Microsoft liste aussi « le processus se réfère à une page virtuelle allouée pour la première fois » comme exemple de défaut souple.5
Le demand-zero a les caractéristiques suivantes.
- Il n’y a pas besoin de lire des données d’origine depuis le disque
- Le contenu initial est zéro
- Une page physique disponible est liée
- Le Working Set et le Page Fault Count cumulé augmentent
- Ce traitement seul n’augmente pas
Memory\\Pages Input/sec
C’est pourquoi un pic de Page Faults/sec juste après le démarrage ne signifie pas à lui seul que le stockage est le goulot.
Le compromis de l’allocation paresseuse mérite aussi d’être clarifié. Si vous Committez 256 MiB et n’en utilisez réellement que 8 MiB, laisser les 248 MiB restants hors de la RAM est raisonnable. En échange, le premier accès porte le coût du traitement du défaut. Pour un travail sensible à la latence, il existe une conception qui touche chaque page avant de commencer afin de précharger (prefault), mais c’est un compromis qui augmente d’emblée la résidence en RAM.
8. Défauts souples et défauts durs
8.1. Défauts souples
Un défaut souple est un défaut qui peut se résoudre sans E/S de lecture vers un magasin de soutien. Les exemples représentatifs incluent les suivants.
- Demand-zero
- Reconnecter une page qui reste sur Standby/Transition
- Connecter une page partagée qui est dans le Working Set d’un autre processus
- Connecter une page préchargée
- Copie à l’écriture dont la page d’origine est résidente
Il reste un coût processeur pour la transition noyau, les verrous, les mises à jour PTE/PFN, la cohérence TLB, et ainsi de suite, mais il n’y a pas d’attente de stockage.5
8.2. Défauts durs
En revanche, quand la page nécessaire n’est nulle part en RAM et doit être lue depuis un magasin de soutien, c’est un défaut dur. La source de lecture n’est pas seulement le fichier d’échange.
- Une page privée qui a été écrite dans le fichier d’échange
- Un fichier mappé en mémoire
- Une image EXE ou DLL
- Un fichier de données référencé par le cache de fichiers
Les événements ETW HardFault incluent FileObject, ReadOffset et ByteCount, donc vous pouvez suivre la source de lecture réelle.6
Par conséquent Hard Fault = une lecture de pagefile.sys n’est pas vrai.
Quand une lecture du magasin de soutien est requise, la demande entre dans la pile d’E/S Windows. Le flux des IRP et de l’émission/achèvement est couvert dans « Les profondeurs de l’I/O Windows (partie 1) », et la jonction avec le cache de fichiers est couverte dans « Les profondeurs de l’E/S Windows (épisode 4) ». Si la page est en RAM, le gestionnaire de mémoire peut revenir tout seul ; sinon, il émet une E/S et attend le thread fautif jusqu’à l’achèvement.
9. Un défaut irrésolvable devient une exception
Un défaut qui, après examen du VAD et de la PTE, ne peut pas se résoudre comme une allocation légitime, un page-in ou un CoW est livré au mode utilisateur comme une exception.
Le cas représentatif est STATUS_ACCESS_VIOLATION, code d’exception 0xC0000005. Il se produit sur une lecture, une écriture ou une exécution d’une adresse invalide ; le premier paramètre d’exception indique le type d’accès et le second l’adresse fautive.7
Les motifs typiques incluent les suivants.
- Lire NULL, une adresse libérée, ou une adresse hors tableau
- Écrire vers une page en lecture seule
- Exécuter une instruction depuis une page que DEP/NX a rendue non exécutable
- Toucher une plage réservée qui n’est pas commise
PAGE_GUARD a un sens un peu différent. C’est une notification unique d’accès : elle lève STATUS_GUARD_PAGE_VIOLATION et sert à des choses telles que la croissance de pile.8
L’allocation paresseuse normale, le page-in, le CoW, la notification de garde et une violation d’accès finale se rassemblent, du point de vue du processeur, au même point d’entrée de défaut de page. Ce qui décide du résultat est la combinaison de VAD, PTE, attributs de protection et type d’accès.
10. Voyez-le vous-même
Vous pouvez observer le flux jusqu’ici sur votre propre machine. Le programme C++ suivant Reserve 256 MiB, le Commit, écrit un octet sur chaque page, et enfin Release. Il attend Entrée à chaque étape pour que vous puissiez observer les changements dans VMMap et PerfMon.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <psapi.h>
#include <cstdio>
#include <cstdlib>
#pragma comment(lib, "Psapi.lib")
constexpr SIZE_T kSize = 256ull * 1024 * 1024;
void PrintMemory(const char* stage)
{
PROCESS_MEMORY_COUNTERS_EX c{};
c.cb = sizeof(c);
if (!GetProcessMemoryInfo(
GetCurrentProcess(),
reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&c),
sizeof(c))) {
std::printf("GetProcessMemoryInfo failed: %lu\n", GetLastError());
return;
}
std::printf(
"%-10s WS=%zu MiB Private=%zu MiB Faults=%lu\n",
stage,
c.WorkingSetSize / 1024 / 1024,
c.PrivateUsage / 1024 / 1024,
c.PageFaultCount);
}
void Pause(const char* message)
{
PrintMemory(message);
std::puts("Press Enter...");
(void)std::getchar();
}
int main()
{
SYSTEM_INFO si{};
GetSystemInfo(&si);
std::printf("PID=%lu, page=%lu bytes\n",
GetCurrentProcessId(), si.dwPageSize);
void* base = VirtualAlloc(nullptr, kSize, MEM_RESERVE, PAGE_NOACCESS);
if (!base) {
std::fprintf(stderr, "Reserve failed: %lu\n", GetLastError());
return EXIT_FAILURE;
}
Pause("reserved");
if (!VirtualAlloc(base, kSize, MEM_COMMIT, PAGE_READWRITE)) {
std::fprintf(stderr, "Commit failed: %lu\n", GetLastError());
VirtualFree(base, 0, MEM_RELEASE);
return EXIT_FAILURE;
}
Pause("committed");
auto* bytes = static_cast<volatile unsigned char*>(base);
for (SIZE_T offset = 0; offset < kSize; offset += si.dwPageSize) {
bytes[offset] = 1;
}
Pause("touched");
if (!VirtualFree(base, 0, MEM_RELEASE)) {
std::fprintf(stderr, "Release failed: %lu\n", GetLastError());
return EXIT_FAILURE;
}
Pause("released");
}
Depuis l’invite de commandes Native Tools x64 de Visual Studio, vous pouvez compiler avec la commande suivante.
cl /std:c++20 /EHsc /W4 memory_fault_demo.cpp
10.1. Quoi regarder dans VMMap
VMMap est un outil qui affiche la mémoire virtuelle réservée, le Commit, le Working Set, Private et Shareable par type.9 Les changements à attendre à chaque étape sont les suivants.
| Étape | Changement attendu |
|---|---|
| Reserve | Address Space Size augmente, mais Commit/WS n’augmentent pas du même montant |
| Commit | Private Commit augmente d’environ 256 MiB |
| Touch | Working Set et Private WS augmentent nettement, et le Fault Count aussi |
| Release | La plage cible disparaît, et Commit et WS baissent |
Les chiffres réels varient avec le runtime, les produits de sécurité, la pression mémoire et le moment où vous observez. Regardez dans quel sens les chiffres ont bougé entre les étapes, pas s’ils sortent exactement à 256 MiB.
10.2. Séparer souple et dur dans PerfMon
Dans PerfMon, placez les compteurs suivants sur le même axe temporel.
Process(<target>)\\Page Faults/secMemory\\Pages Input/secMemory\\Page Reads/secMemory\\Available MBytesProcess(<target>)\\Working Set - PrivateProcess(<target>)\\Private Bytes
Process\\Page Faults/sec inclut à la fois les défauts souples et durs. Memory\\Pages Input/sec, en revanche, est le nombre de pages lues depuis le disque pour résoudre des défauts durs.10
À l’étape Touch de ce programme, Page Faults/sec devrait sauter tandis que Pages Input/sec ne devrait pas beaucoup monter. Les pages nouvellement commises sont matérialisées par demand-zero, donc il n’y a pas besoin de lire des données d’origine depuis le disque.
Quand plusieurs processus partagent le même nom, des numéros PerfMon tels que process#1 peuvent changer d’un redémarrage à l’autre. Croisez avec un compteur qui affiche le PID, ou identifiez par PID avec Process V2 ou ETW/WPA.
11. Trois lectures erronées à éviter en pratique
11.1. « Le Commit a monté, donc c’est une fuite de RAM »
Le Commit est le montant promis de contenu à conserver ; les pages non touchées peuvent ne pas être résidentes en RAM. Pour juger une fuite, regardez la série temporelle des Private Bytes, la ventilation des allocations, et si le chiffre revient à une ligne de base après la fin du traitement.
11.2. « Page Faults/sec est élevé, donc le disque est lent »
Les défauts souples n’impliquent aucune E/S disque. Séparez Page Faults/sec, Pages Input/sec et l’attente de stockage, et si besoin suivez le fichier source et la pile avec les événements ETW HardFault.
11.3. « Vider le Working Set va corriger la fuite »
Retirer une page du Working Set ne libère ni le Commit ni la propriété. La page passe en Standby ou Modified et fautera plus tard pour revenir. Corriger une fuite exige que l’allocateur fasse VirtualFree, une libération de tas, une destruction d’objet, et ainsi de suite.
Où va cette page physique retirée, c’est ce que nous suivons dans la partie 2.
12. Résumé
MEM_RESERVEmet de côté une plage d’adresses virtuelles mais n’attribue aucune région physique en RAM ni dans le fichier d’échange.1MEM_COMMITconsomme du Commit et garantit que le contenu pourra être conservé à l’avenir, mais une page physique ordinaire n’est pas attribuée avant le premier accès.12- Le VAD est le registre de plages, la PTE le registre de pages virtuelles, et la base PFN le registre de pages physiques.
- Un échec TLB n’est pas un défaut de page. Si la PTE est valide, un parcours de table de pages seul le résout.
- Demand-zero, restauration Transition et connexion d’une page partagée sont des défauts souples qui se résolvent sans E/S disque.5
- Si une lecture depuis le fichier d’échange, une DLL, un EXE ou un fichier mappé est requise, c’est un défaut dur.6
- Si l’inspection du VAD, de la PTE et des attributs de protection ne peut pas résoudre le défaut, vous obtenez une exception telle que
0xC0000005.7 - Pour un jugement de performance, ne regardez pas
Page Faults/secseul ; regardezPages Input/sec, Available, Working Set, Private Bytes et l’attente de stockage sur le même axe temporel.
La suite est la partie 2, « La vie d’une page physique : cinq listes et la vérité sur le fichier d’échange ».
Après que la promesse de Commit a été tournée en page physique, nous suivons où va cette page quand elle quitte le Working Set, depuis la base PFN et les listes de pages.
Articles connexes
- Que représente réellement la « mémoire utilisée » sous Windows ── Bien lire Working Set, Private Bytes, Commit et le fichier d’échange
- Les profondeurs de l’I/O Windows (partie 1) — Chaque lecture et écriture devient un IRP : la vue d’ensemble du système d’E/S
- Les profondeurs de l’E/S Windows (épisode 4) — Le gestionnaire de cache : quand votre WriteFile atteint-il vraiment le disque ?
- Lire un dump de plantage avec WinDbg + SOS — Guide pratique d’analyse après la collecte
- Introduction à la collecte des dumps de crash Windows - WER/ProcDump/WinDbg
Domaines de conseil associés
KomuraSoft LLC mène des investigations sur l’usage mémoire des applications Windows, les violations d’accès, les retards au démarrage, la pagination et les défauts de code natif.
- Développement d’applications Windows
- Investigation de bugs et analyse des causes
- Migration d’actifs hérités
- Nous contacter
Références
-
Microsoft Learn, VirtualAlloc function. Sur le fait que
MEM_RESERVEréserve une plage d’adresses virtuelles sans attribuer de stockage physique ; queMEM_COMMITimpute une charge de commit à la mémoire et au fichier d’échange du système ; que le contenu initial d’une page commise est zéro ; et que la page physique réelle n’est pas attribuée tant qu’elle n’est pas accédée. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 -
Microsoft Learn, PERFORMANCE_INFORMATION structure. Sur le fait que
CommitTotalest le nombre actuel de pages Commit du système, et queCommitLimitest la borne supérieure que l’on peut commiter sans étendre le fichier d’échange. ↩ ↩2 -
Microsoft Learn, !vad (WinDbg). Sur le fait que
!vadaffiche l’arbre VAD et permet d’inspecter les VPN de début et de fin, le Commit, Mapped/Private, les attributs de protection, la Control Area, et plus. ↩ -
Microsoft Learn, PageFault_TypeGroup1 class. Sur le fait qu’ETW distingue et enregistre Transition Fault, Demand Zero Fault, Copy-on-Write, Guard Page Fault, Hard Page Fault et Access Violation. ↩
-
Microsoft Learn, Working Set. Sur le fait qu’un défaut souple se résout sans accéder à un magasin de soutien, et qu’il survient depuis le Working Set d’un autre processus, Transition, demand-zero de première référence, et ainsi de suite. ↩ ↩2 ↩3
-
Microsoft Learn, PageFault_HardFault class. Sur le fait qu’un événement HardFault inclut FileObject, ReadOffset, ByteCount, VirtualAddress et un identifiant de thread, de sorte que la source de lecture peut être suivie. ↩ ↩2
-
Microsoft Learn, Access Violation C0000005. Sur le fait que
0xC0000005se produit sur une lecture, une écriture ou une exécution d’une adresse mémoire invalide, et que les paramètres d’exception indiquent le type d’accès et l’adresse fautive. ↩ ↩2 -
Microsoft Learn, Creating Guard Pages. Sur le fait que
PAGE_GUARDfournit une notification unique d’accès à la page et lèveSTATUS_GUARD_PAGE_VIOLATION. ↩ -
Microsoft Learn, VMMap - Sysinternals. Sur le fait que VMMap ventile la mémoire virtuelle commise par type et affiche le Working Set de chaque type et une carte d’adresses détaillée. ↩
-
Microsoft Learn, Performance Analysis of Logs (PAL) Tool. Sur le fait que
Memory\\Pages Input/secest le nombre de pages lues depuis le disque pour résoudre des défauts de page durs. ↩
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Les profondeurs de la mémoire Windows (partie 2) — La vie d'une page physique : cinq listes et la vérité sur le fichier d'échange
Cet article relie la base PFN, Standby, Modified, la compression mémoire et le fichier d'échange pour expliquer où va une page physique u...
Les profondeurs de la mémoire Windows (partie 3) — Objets section et copie sur écriture : ce que sont vraiment les DLL et le mappage de fichiers
Cet article relie objets section, mappages image et données, cache partagé et copie sur écriture pour expliquer comment DLL et mémoire pa...
Que représente réellement la « mémoire utilisée » sous Windows ── Bien lire Working Set, Private Bytes, Commit et le fichier d'échange
La « mémoire » du Gestionnaire des tâches, Working Set, Private Bytes et Commit ne représentent pas la même valeur. Cet article explique ...
Les profondeurs de la virtualisation Windows (partie 3) — Des machines virtuelles qui démarrent en quelques secondes : pourquoi WSL2, Windows Sandbox et les conteneurs sont si légers
Pourquoi WSL2 et Windows Sandbox démarrent-ils en quelques secondes et paraissent-ils si légers ? Cet article explique les mécanismes, de...
Les profondeurs de la virtualisation Windows (partie 2) — Une mémoire invisible même au noyau : comment fonctionnent VBS, HVCI et Credential Guard
Lors d'une installation propre sur un matériel compatible, VBS est activée par défaut et utilise l'hyperviseur et SLAT pour créer une iso...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Développement d'applications Windows
Applications métier, intégration d'équipements et outils de communication, des besoins au développement.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Passer MEM_COMMIT à VirtualAlloc alloue-t-il de la RAM à cet instant ?
- Dans la mémoire privée ordinaire, le Commit consomme la marge de commit du système, mais la page physique correspondante n'est pas attribuée avant le premier accès. Une page d'abord touchée par une écriture obtient sa page physique pendant le traitement d'un défaut demand-zero.
- Un défaut de page signifie-t-il qu'il y a un problème ou un souci de performance ?
- Non. Les défauts souples sans E/S disque — demand-zero ou retour d'une page depuis Standby — sont un fonctionnement normal. Pour juger la performance, regardez non seulement Page Faults/sec, mais aussi Pages Input/sec, l'attente de stockage et Available MBytes.
- Un échec TLB et un défaut de page sont-ils la même chose ?
- Ce sont des choses différentes. Même si le TLB n'a pas de traduction, si la PTE de la table de pages est valide, le processeur se contente de parcourir la table et de réenregistrer la traduction. Il n'entre dans le défaut de page que si la PTE est invalide ou s'il y a une violation de protection.
- Si la plage d'adresses est dans un VAD, on ne peut pas avoir de violation d'accès ?
- Pas nécessairement. Outre l'existence d'un VAD, le gestionnaire de mémoire évalue Reserve versus Commit, la protection lecture/écriture/exécution, les pages de garde, l'état de la PTE, et plus. Si le défaut ne peut pas être résolu, vous obtenez une exception telle que 0xC0000005.
- Un Page Faults/sec élevé signifie-t-il que le système manque de RAM ?
- On ne peut pas le dire à partir de cela seul. Page Faults/sec inclut aussi un grand nombre de défauts souples. Il faut le corréler sur le même axe temporel avec Memory\Pages Input/sec, Memory\Page Reads/sec, Available MBytes et le temps d'attente disque.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.