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
· Mis à jour le: · Go Komura · Windows, Gestion de la mémoire, VirtualAlloc, Page Fault, VAD, Supervision des performances
Historique des révisions (première version, publiée le 20 Aug 2026)
- Première publication
Citer cet article(DOI (archive enregistrée): 10.5281/zenodo.22176072)
Les DOI ci-dessous renvoient à des versions déjà archivées et peuvent différer du texte actuel. Pour citer le texte actuel, utilisez l’URL de cette page.
Go Komura (2026). 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. KomuraSoft LLC. https://comcomponent.com/fr/blog/windows-memory-internals-page-fault/
- DOI (archive enregistrée)
- 10.5281/zenodo.22176072
- DOI (dernière version enregistrée)
- 10.5281/zenodo.22176073
« J’ai fait un Commit de 256 MiB, mais le Working Set n’augmente pas d’autant. » Cette question, qui revient quand on utilise VirtualAlloc, est le point de départ de la partie 1.
Pour la mémoire privée ordinaire, committer une page et la placer en RAM physique sont deux choses distinctes. Windows retarde l’attribution des pages physiques jusqu’à ce que l’application touche réellement la page. Quand le premier accès provoque un défaut de page, le gestionnaire de mémoire examine le VAD, la PTE, les attributs de protection et le backing store, puis lie la RAM nécessaire une page à la fois.1
Cet article suit le chemin que « le premier octet touché » parcourt jusqu’à la RAM physique. Si vous voulez d’abord clarifier le sens des chiffres 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 : elle creuse, depuis le mécanisme, pourquoi ces chiffres sortent ainsi.
« Les profondeurs de la mémoire Windows » — les 3 parties
Cette série avance dans l’ordre obtenir une page physique → suivre la résidence et la récupération → comprendre le partage et la privatisation.
| Partie | Thème | Ce que cette partie suit |
|---|---|---|
| Partie 1 (cet article) | Adresses virtuelles et défauts de page | Quand une région allouée avec VirtualAlloc obtient de la RAM physique |
| Partie 2 | La vie d’une page physique | Les transitions d’état d’une page sortie du Working Set, et le rôle du fichier d’échange |
| Partie 3 | Objets section et copie sur écriture | Comment les DLL, les mappages de fichiers et la mémoire partagée partagent 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 ?
| Avant de commencer | Contenu |
|---|---|
| Public visé | Développeurs et exploitants qui veulent comprendre, depuis le mécanisme, l’usage mémoire, les défauts de page juste après le démarrage, 0xC0000005, et les chiffres de VMMap et de PerfMon |
| Environnement | Windows 10/11 ou une version actuelle de Windows Server |
| Prérequis | Les pointeurs et les bases de VirtualAlloc |
| Difficulté | Intermédiaire. L’expérience des dispositions de bits des tables de pages ou d’un débogueur noyau n’est pas nécessaire |
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.
Dans le diagramme, un trait continu marque une relation qui vaut toujours et un trait pointillé une relation conditionnelle (les conditions figurent dans l’explication de chaque relation sur la page de détail). La liste complète des relations (14 au total, avec preuve et niveau de certitude) et les définitions des concepts principaux sont rassemblées sur la page de détail de la carte des connaissances (en japonais). Données : JSON-LD / Turtle
1. D’abord la conclusion
Pour la mémoire privée ordinaire, séparer les trois étapes suivantes fait apparaître la différence entre Commit et Working Set.
- Reserve est l’étape qui réserve une adresse dans l’espace virtuel. Elle réserve la plage, mais n’attribue aucune zone de stockage physique en RAM ni dans le fichier d’échange.1
- Commit est l’étape où le système promet de pouvoir conserver le contenu plus tard. Il impute une charge de commit et augmente le Commit Total, mais ne lie en général pas encore de RAM physique à toutes les pages.12
- Touch est l’étape où une page physique devient réellement nécessaire. Le premier accès provoque un défaut de page et, si l’accès est légitime, le gestionnaire de mémoire attribue une page physique et réexécute l’instruction.
MEM_COMMIT n’est pas un ordre qui dit « alloue de la RAM tout de suite ». Ce n’est pas non plus une promesse en l’air : c’est une promesse à l’échelle du système que le contenu pourra être conservé plus tard, en RAM ou dans un backing store approprié. Le fait que le contenu initial d’une page en Commit soit zéro, et le fait qu’aucune page physique ne soit attribuée avant le premier accès, sont parfaitement compatibles.1
L’idée selon laquelle « Reserve/Commit n’écrivent que dans le VAD » est elle aussi inexacte. Reserve crée surtout un VAD qui représente la plage et ses attributs ; Commit augmente le Commit Total du système et enregistre l’état commité de la plage. Les niveaux intermédiaires de la table de pages et les PTE individuelles sont construits de façon différée, au moment où ils deviennent nécessaires.
| Ce que vous voulez savoir | Sections à lire |
|---|---|
| Ce qui change à Reserve, Commit et Touch | Sections 2 à 3 |
| Ce que décident le VAD, la PTE et le TLB | Sections 4 à 6 |
| Séparer les défauts normaux des attentes d’E/S et des exceptions | Sections 7 à 9 |
| Vérifier sur les chiffres de votre machine | Sections 10 à 11 |
flowchart TB
accTitle: Ce qui se produit à 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["Enregistrement de la plage et des attributs dans le VAD"]
commit -.-> charge["Consommation du Commit Total (pas encore de page physique)"]
touch --> fault["Défaut de page"]
fault --> zero["Liaison d'une page physique mise à zéro à la PTE"]
zero --> ws["Ajout au Working Set et réexécution de l'instruction"]
Figure 1 : Reserve, Commit et Touch sont des événements distincts. La RAM physique n’est liée qu’à la dernière étape, le premier accès.
2. Trois registres pour suivre une page virtuelle
Les registres que tient Windows regardent la même mémoire selon des unités différentes. Distinguons d’abord les trois : plage, page virtuelle et page physique.
| Registre | Unité | Rôle |
|---|---|---|
| VAD | Plage d’adresses virtuelles | Gère la nature de la région, Reserve/Commit, la protection et la correspondance avec une section |
| Table de pages / PTE | Page virtuelle | Représente la traduction actuelle vers une page physique, ou un état non encore matérialisé |
| Base PFN | Page physique | Suit la propriété, les références et l’état de chaque page de RAM |
Le VAD porte l’information d’une plage, la PTE celle d’une page virtuelle, et la base PFN celle d’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 de l'adresse virtuelle à la RAM physique
accDescr: Une adresse virtuelle est gérée par le VAD à la granularité de la plage et par la PTE à la granularité de la page virtuelle, et la base PFN suit, à la granularité de la page physique, la page physique vers laquelle la PTE traduit
va["Adresse virtuelle"] --> vad["VAD (registre des plages)"]
va --> pte["PTE (registre des pages virtuelles)"]
vad -.->|Évalue Reserve/Commit et la protection| pte
pte -->|Traduction valide| pfn["Base PFN (registre des pages physiques)"]
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 applique le résultat côté PFN.
Cet article a pour protagonistes le VAD et la PTE. La partie 2 regardera la base PFN depuis le côté page physique.
3. Reserve, Commit et Touch sont des événements distincts
3.1. Reserve — réserver une adresse
Réservons d’abord une plage d’adresses virtuelles contiguë de 256 MiB.
void* base = VirtualAlloc(
nullptr,
256ull * 1024 * 1024,
MEM_RESERVE,
PAGE_NOACCESS);
À ce stade, tout ce qui s’est produit, c’est qu’une adresse a été réservée dans l’espace virtuel du processus pour que d’autres allocations ne puissent pas utiliser cette plage. MEM_RESERVE n’attribue aucune zone de stockage physique, ni en RAM ni dans le fichier d’échange.1
Parce qu’un processus 64 bits dispose d’un vaste espace virtuel, une conception qui réserve d’abord une grande plage et ne committe plus tard que les parties nécessaires devient réaliste.
3.2. Commit — promettre que le contenu pourra être conservé
Ensuite, on committe la plage déjà réservée.
void* committed = VirtualAlloc(
base,
256ull * 1024 * 1024,
MEM_COMMIT,
PAGE_READWRITE);
En cas de succès, la quantité promise augmente : elle se reflète dans le Commit Total du système et, en général, dans les Private Bytes du processus. Pour autant, 256 MiB de pages physiques ne se rangent pas d’un coup. Les pages ordinaires restent physiquement non attribuées jusqu’au premier accès.12
Alors, à quoi sert le Commit ? À ceci : si le système ne peut pas prendre la promesse, il peut renvoyer un échec au moment du Commit, et non 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 page de tête.
static_cast<unsigned char*>(base)[0] = 1;
Le processeur tente de traduire l’adresse virtuelle en adresse physique, mais la PTE n’a pas encore de traduction valide vers une page physique. C’est là que le défaut de page se produit.
Le gestionnaire de mémoire, qui reçoit le contrôle, détermine qu’il s’agit d’un « premier accès à une page privée en Commit et accessible en écriture », obtient une page physique mise à zéro, la lie à la PTE et l’ajoute au Working Set. Il fait ensuite réexécuter l’instruction d’écriture qui a échoué.
Du point de vue de l’application, ce n’est qu’une affectation. 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 — registre des plages de l’espace virtuel
VAD est l’abréviation de Virtual Address Descriptor : Windows gère les plages d’adresses utilisées par un processus sous forme d’arbre de VAD. La commande !vad de WinDbg permet d’inspecter le VPN de début et de fin, le Commit, les attributs de protection, Private/Mapped, la Control Area, et d’autres champs.3
Les informations représentatives portées par un VAD sont les suivantes.
- Le début et la fin de la plage d’adresses
- Le type : Private, Mapped, Image, etc.
- L’état Reserve/Commit
- La protection : lecture, écriture, exécution, Copy-on-Write, etc.
- La correspondance avec un fichier ou une section
- Des attributs spéciaux tels que les pages de garde
On les tient par plage pour réduire le coût de gestion. 256 MiB représentent 65 536 pages de 4 KiB.
Plutôt que de construire dès le départ une structure de gestion complète pour chaque page, le VAD gère « cette plage contiguë est une seule réservation ». Ensuite, les pages se matérialisent au fur et à mesure des besoins.
4.1. Trouver un VAD ne garantit pas que le défaut puisse être résolu
L’explication « s’il est dans un VAD, le défaut se résout ; sinon, violation d’accès » est commode comme porte d’entrée, mais elle simplifie trop. Même quand un VAD est trouvé, un accès ordinaire ne peut pas continuer dans des cas tels que les suivants.
- Seul Reserve a été fait, et la page visée n’est pas en Commit
- La page est
PAGE_NOACCESS - Une écriture a été faite sur une page en lecture seule
- Une instruction a été exécutée depuis une page non exécutable
- Une page de garde a été touchée pour la première fois
- L’accès est sorti de la plage valide d’une section
À l’inverse, même si la PTE est invalide, si l’état logiciel du VAD et de la PTE montre que l’accès est légitime, on peut le résoudre en demand-zero, restauration Transition, page-in ou CoW. Pour être précis, on évalue ensemble le VAD, la PTE, les attributs de protection et le type d’accès.
5. Tables de pages et TLB
Le pointeur que détient l’application est une adresse virtuelle. Pour que le processeur accède à la RAM, il doit traduire le 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 terminale est la PTE (Page Table Entry).
Une PTE valide porte, conceptuellement, le PFN, la protection lecture/écriture/exécution, l’autorisation en mode utilisateur, Accessed/Dirty, et d’autres informations. La disposition réelle des bits dépend du processeur et de la version de Windows.
Cela dit, parcourir la table de pages à chaque accès serait trop lent, donc le processeur met en cache les traductions récentes dans le TLB (Translation Lookaside Buffer). La traduction d’adresse avance dans l’ordre suivant.
- Si le TLB a une traduction et que l’accès est conforme à sa protection, ce résultat est utilisé.
- Si le TLB n’a pas de traduction, le processeur parcourt la table de pages.
- S’il existe une PTE valide et que l’accès est aussi conforme à la protection, la traduction 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, on entre par le point d’entrée du défaut de page. La vérification de protection a lieu aussi lorsque la traduction vient du TLB.
Le point facile à confondre ici, c’est qu’un échec TLB et un défaut de page sont distincts.
| Situation | Ce qui se produit ensuite |
|---|---|
| Le TLB a une traduction et l’accès est conforme à la protection | Continuer avec la traduction en cache |
| Le TLB n’a pas de traduction, mais il existe une PTE valide et l’accès est conforme à la protection | Obtenir la traduction par un parcours de table de pages et continuer |
| Il n’y a pas de traduction valide, ou l’accès viole la protection | Entrer par le point d’entrée du défaut de page |
La vérification de protection fonctionne aussi sur un succès TLB. Une écriture sur une page en lecture seule, ou l’exécution d’une instruction sur une page non exécutable, provoque un défaut même si la traduction est déjà en cache. C’est aussi pour cela qu’une écriture sur une page CoW peut provoquer un défaut.
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 accès non conforme à la protection entre par le point d'entrée du défaut de page. Si le TLB n'a pas de traduction, on parcourt la table de pages ; une PTE valide dont la protection est aussi conforme est enregistrée dans le TLB et l'exécution continue ; une traduction invalide ou une violation de protection entre par le 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 est-il conforme à la protection ?"}
perm -->|Conforme| 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 la table de pages"]
walk --> valid{"PTE valide et protection aussi conforme ?"}
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. On entre dans un défaut de page quand la traduction est invalide ou qu’il y a une violation de protection, et une violation de protection peut aussi se produire sur un succès TLB.
5.1. Une PTE invalide n’est pas une simple case vide
Dire qu’une PTE est invalide ne signifie pas que son contenu est vide. À partir de l’état logiciel d’une PTE invalide, Windows distingue par exemple les cas suivants.
- Une page demand-zero jamais encore matérialisée
- Une page Transition qui reste en RAM
- Une page partagée qui référence une Prototype PTE
- Une page privée enregistrée dans le fichier d’échange
- Une violation de protection ou une région invalide
Le travail du processeur s’arrête à juger « ce n’est pas une traduction valide ordinaire » et à passer la main au noyau ; c’est le gestionnaire de mémoire qui donne le sens ensuite.
6. Un défaut de page de bout en bout
Suivons une première écriture sur une page privée en Commit, en six étapes.
- Le processeur tente d’écrire.
Il examine le TLB et la table de pages, mais la PTE cible n’a pas de PFN valide. - Le processeur déclenche un défaut de page.
Il transmet au noyau l’adresse virtuelle en défaut, le type lecture/écriture/exécution, utilisateur/noyau, et s’il s’agit d’une traduction absente ou d’une violation de protection. - Le gestionnaire de mémoire examine le VAD et la PTE.
Il décide si la page est en Commit, si l’accès est conforme à la protection, et laquelle des voies s’applique : demand-zero, Transition, partagée, page-in, CoW ou exception. - S’il s’agit d’un demand-zero, une page physique mise à zéro est obtenue.
Une page nouvellement remise doit être à zéro, pour ne pas fuiter les données d’un autre processus. - La PTE et les informations de gestion PFN sont mises à jour.
Le PFN et la protection sont écrits dans la PTE, la page physique passe Active, et elle est ajoutée au Working Set du processus. - L’instruction qui a échoué est réexécutée.
Comme le défaut s’est résolu normalement, aucune exception en mode utilisateur n’est livrée, et l’application continue comme s’il s’agissait d’une affectation ordinaire.
Les événements de défaut de page d’ETW enregistrent aussi Transition, Demand Zero, Copy-on-Write, Guard Page, Hard Page Fault et Access Violation comme des types distincts.4
Autrement dit, un défaut de page n’est pas, dès le départ, un mot qui signifie « anomalie ». C’est le point d’entrée commun pour demander à l’OS de décider, lorsque le processeur n’a pas pu traduire par le chemin ordinaire.
flowchart LR
accTitle: Où un défaut de page se résout
accDescr: Le gestionnaire de mémoire évalue le VAD, la PTE, les attributs de protection et le type d'accès, et oriente vers un demand-zero, une reconnexion d'une page encore en RAM, un défaut matériel depuis un backing store, une copie sur écriture, une notification de page de garde, ou une exception
faultIn["Survenue du défaut de page"] --> judge["Évaluation VAD, PTE, protection, type"]
judge -->|Premier accès| dz["Demand-zero (logiciel)"]
judge -->|Encore en RAM| soft["Reconnexion depuis Standby, etc. (logiciel)"]
judge -->|Lecture disque requise| hard["Défaut matériel (E/S disque)"]
judge -->|Écriture CoW| cow["Copie et remplacement de la PTE"]
judge -->|Page de garde| guard["Levée de la garde et notification"]
judge -->|Non résoluble| av["Exception (0xC0000005, etc.)"]
Figure 4 : Les défauts qui entrent par le même point d’entrée se séparent en six issues selon le résultat de l’évaluation. Le détail des pages de garde est traité à la section 9.
7. Demand-zero — un défaut logiciel qui ne lit pas le disque
Le demand-zero est le défaut logiciel représentatif qui se produit lorsqu’on touche pour la première fois une page privée en Commit. La documentation Microsoft sur le Working Set cite aussi, comme exemple de défaut logiciel, le cas où « le processus référence pour la première fois une page virtuelle allouée ».5
Le demand-zero a les caractéristiques suivantes.
- Il n’est pas nécessaire 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 saturé.
7.1. L’allocation différée échange de la RAM contre le coût du premier accès
Si vous committez 256 MiB mais n’en utilisez réellement que 8 MiB, l’allocation différée, qui évite de placer les 248 MiB restants en RAM, est raisonnable. En échange, le premier accès porte le coût du traitement du défaut.
Pour un traitement sensible à la latence, on choisit parfois de « prefault » en touchant chaque page avant de commencer. Ce n’est toutefois pas une optimisation gratuite. C’est le choix de terminer d’avance le traitement du premier accès, en augmentant d’avance aussi la quantité résidente en RAM.
8. Défauts logiciels et défauts matériels
La ligne de partage est la nécessité ou non d’une E/S de lecture depuis un backing store. Le nombre de défauts de page, à lui seul, ne révèle pas cette différence.
8.1. Défauts logiciels
Un défaut logiciel est un défaut que l’on peut résoudre sans E/S de lecture vers un backing store. Voici des exemples représentatifs.
- Demand-zero
- Reconnexion d’une page qui reste en Standby/Transition
- Connexion d’une page partagée présente dans le Working Set d’un autre processus
- Connexion d’une page déjà préchargée
- Copy-on-Write dont la page d’origine est résidente
Il y a un coût processeur pour la transition noyau, les verrous, les mises à jour PTE/PFN, la cohérence du TLB, etc., mais il n’y a pas d’attente de stockage.5
8.2. Défauts matériels
En revanche, lorsque la page nécessaire n’est nulle part en RAM et doit être lue depuis un backing store, c’est un défaut matériel. La source de lecture n’est alors pas seulement le fichier d’échange.
- Une page privée évacuée vers 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 HardFault d’ETW incluent FileObject, ReadOffset et ByteCount, ce qui permet de suivre la source de lecture réelle.6
Donc Hard Fault = lecture de pagefile.sys est faux.
Quand une lecture de backing store devient nécessaire, la demande entre dans la pile d’E/S de Windows. Le flux des IRP et de l’émission/complétion est traité dans « Les profondeurs de l’E/S Windows (partie 1) », et la jonction avec le cache de fichiers dans « Les profondeurs de l’E/S Windows (partie 4) ». Si la page est en RAM, le gestionnaire de mémoire peut revenir seul ; sinon, il émet une E/S et fait attendre le thread en défaut jusqu’à la complétion.
9. Un défaut non résoluble devient une exception
Un défaut qui, même après examen du VAD et de la PTE, ne peut pas être résolu comme une allocation légitime, un page-in ou un CoW, est livré en mode utilisateur sous forme d’exception.
9.1. Les cas qui deviennent une violation d’accès
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 en infraction.7
Les schémas typiques d’occurrence sont les suivants.
- Lire NULL, une adresse déjà libérée, ou une adresse hors tableau
- Écrire sur une page en lecture seule
- Exécuter une instruction depuis une page rendue non exécutable par DEP/NX
- Toucher une plage en Reserve qui n’est pas en Commit
9.2. Une page de garde sert de notification unique
PAGE_GUARD a un sens un peu différent. C’est un mécanisme qui notifie un accès une seule fois, en levant STATUS_GUARD_PAGE_VIOLATION, et il sert notamment à l’extension de pile.8
L’allocation différée normale, le page-in, le CoW, la notification de garde et la 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 l’issue, c’est la combinaison du VAD, de la PTE, des attributs de protection et du type d’accès.
10. Le vérifier de vos propres yeux
Le but de l’expérience est d’observer séparément l’étape où le Commit augmente et celle où le Working Set augmente.
Le programme C++ suivant réserve 256 MiB, les committe, écrit un octet dans chaque page, puis les libère. Il attend la touche Entrée à chaque étape, afin que vous puissiez y vérifier les valeurs 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 x64 Native Tools de Visual Studio, vous pouvez compiler avec la commande suivante.
cl /std:c++20 /EHsc /W4 memory_fault_demo.cpp
10.1. Ce qu’il faut regarder dans VMMap
VMMap est un outil qui affiche, par type, la mémoire virtuelle réservée, le Commit, le Working Set, Private et Shareable.9 Les changements attendus à chaque étape sont les suivants.
| Étape | Changement attendu |
|---|---|
| Reserve | La Size de Address Space augmente, mais Commit/WS n’augmentent pas d’autant |
| Commit | Le Commit Private augmente d’environ 256 MiB |
| Touch | Le Working Set et le Private WS augmentent fortement, et le Fault Count aussi |
| Release | La plage cible disparaît, et le Commit et le WS baissent |
Regarder le changement entre étapes, pas la coïncidence des chiffres
Les chiffres réels varient avec le runtime, les produits de sécurité, la pression mémoire et le moment de l’observation. Ce n’est pas de savoir s’ils tombent pile sur 256 MiB qui compte, mais dans quel sens ils ont bougé d’une étape à l’autre.
10.2. Séparer logiciel et matériel dans PerfMon
Dans PerfMon, placez les compteurs suivants sur le même axe temporel.
Process(<cible>)\\Page Faults/secMemory\\Pages Input/secMemory\\Page Reads/secMemory\\Available MBytesProcess(<cible>)\\Working Set - PrivateProcess(<cible>)\\Private Bytes
Process\\Page Faults/sec inclut à la fois les défauts logiciels et les défauts matériels. Memory\\Pages Input/sec, lui, est le nombre de pages lues depuis le disque pour résoudre des défauts matériels.10
À l’étape Touch de ce programme, Page Faults/sec devrait s’envoler sans que Pages Input/sec n’augmente beaucoup. Les pages nouvellement commitées se matérialisent par demand-zero, donc il n’est pas nécessaire de lire des données d’origine depuis le disque.
Confirmer aussi par PID les processus homonymes
Lorsque plusieurs processus portent le même nom, les numéros PerfMon du type process#1 peuvent changer à un redémarrage. Croisez avec un compteur qui affiche le PID, ou identifiez le processus par PID avec Process V2 ou ETW/WPA.
11. Trois lectures erronées à éviter sur le terrain
11.1. « Le Commit a augmenté, donc c’est une fuite de RAM »
Le Commit est la quantité promise à conserver, et les pages non touchées peuvent ne pas être résidentes en RAM. Pour juger une fuite, on regarde l’évolution temporelle des Private Bytes, la ventilation des allocations, et si la valeur revient à la ligne de base après le traitement.
11.2. « Page Faults/sec est élevé, donc le disque est lent »
Les défauts logiciels n’entraînent pas d’E/S disque. Séparez Page Faults/sec, Pages Input/sec et l’attente de stockage et, si besoin, suivez jusqu’au fichier source et à la pile avec les événements HardFault d’ETW.
11.3. « Vider le Working Set corrigera la fuite »
Retirer des pages du Working Set ne libère ni le Commit ni la propriété. Les pages passent en Standby ou Modified et reviendront plus tard par un défaut. Pour corriger une fuite, l’allocateur doit faire un VirtualFree, une libération de tas, une destruction d’objet, ou l’équivalent.
Où va ensuite cette page physique retirée, c’est ce que suit la partie 2.
12. Synthèse
MEM_RESERVEréserve une plage d’adresses virtuelles, mais n’attribue aucune zone physique en RAM ni dans le fichier d’échange.1MEM_COMMITconsomme du Commit et garantit que le contenu pourra être conservé plus tard, mais une page physique ordinaire n’est pas attribuée avant le premier accès.12- Le VAD est le registre des plages, la PTE celui des pages virtuelles, et la base PFN celui des pages physiques.
- Un échec TLB n’est pas un défaut de page. S’il existe une PTE valide, un parcours de table de pages suffit à le résoudre.
- Le demand-zero, la restauration Transition et la connexion d’une page partagée sont des défauts logiciels résolubles sans E/S disque.5
- S’il faut lire depuis le fichier d’échange, une DLL, un EXE ou un fichier mappé, c’est un défaut matériel.6
- Si l’examen du VAD, de la PTE et des attributs de protection ne peut pas résoudre le défaut, il devient une exception telle que
0xC0000005.7 - Pour juger la performance, ne vous fiez pas au seul
Page Faults/sec: 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 avoir transformé la promesse de Commit en page physique, nous suivrons, via la base PFN et les listes de pages, où va cette page une fois sortie du Working Set.
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’E/S 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 (partie 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
Chez KomuraSoft, nous prenons en charge l’investigation de l’usage mémoire des applications Windows, les violations d’accès, les lenteurs au démarrage, la pagination et l’analyse des anomalies du code natif.
- Développement d’applications Windows
- Investigation de bugs et analyse des causes
- Valorisation et migration des actifs existants
- Contact
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 sur la mémoire et le fichier d’échange du système, que le contenu initial d’une page en Commit 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 ↩7 ↩8 -
Microsoft Learn, PERFORMANCE_INFORMATION structure. Sur le fait que
CommitTotalest le nombre actuel de pages en Commit du système, et queCommitLimitest le plafond que l’on peut committer sans étendre le fichier d’échange. ↩ ↩2 ↩3 -
Microsoft Learn, !vad (WinDbg). Sur le fait que
!vadaffiche l’arbre des VAD et permet d’inspecter le VPN de début et de fin, le Commit, Mapped/Private, les attributs de protection, la Control Area, et d’autres champs. ↩ -
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 logiciel peut se résoudre sans accès à un backing store, et qu’il se produit depuis le Working Set d’un autre processus, Transition, un demand-zero de première référence, etc. ↩ ↩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, ce qui permet de suivre la source de lecture. ↩ ↩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 en infraction. ↩ ↩2 -
Microsoft Learn, Creating Guard Pages. Sur le fait que
PAGE_GUARDfournit une notification unique d’accès à une page et lèveSTATUS_GUARD_PAGE_VIOLATION. ↩ -
Microsoft Learn, VMMap - Sysinternals. Sur le fait que VMMap décompose la mémoire virtuelle en Commit par type et affiche le Working Set de chaque type ainsi qu’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 un défaut de page matériel. ↩
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 à l'écriture : ce que sont vraiment les DLL et le mappage de fichiers
Cet article relie les objets section, les mappages image et de données, le cache partagé et la copie à l'écriture pour expliquer comment ...
Que représente réellement l'« utilisation mémoire » sous Windows — Lire correctement 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 sont pas la même valeur. Cet article explique le rappo...
Comment un raccourci Windows retrouve-t-il un fichier déplacé ? — L'emplacement d'un fichier et son identité sont deux choses distinctes
Pourquoi un raccourci ouvre-t-il encore un fichier déplacé ? Windows peut retrouver la cible à partir d'identifiants de suivi et des cara...
Faut-il encore « retirer le périphérique en toute sécurité » ? — Réfléchir à partir du retrait rapide et du cache d'écriture
Peut-on retirer une clé USB dès la fin de la copie ? Le cache d'écriture, Retrait rapide contre Meilleures performances, comment vérifier...
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 ?
- Pour la mémoire privée ordinaire, le Commit consomme la marge de commit du système, mais les pages physiques correspondantes ne sont pas attribuées 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 une anomalie ou un problème de performance ?
- Non. Les défauts logiciels sans E/S disque, comme un demand-zero ou le retour d'une page depuis Standby, font partie du fonctionnement normal. Pour juger la performance, ne vous fiez pas au seul Page Faults/sec : regardez 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 deux choses distinctes. 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. On 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 figure dans un VAD, une violation d'accès est-elle impossible ?
- Pas nécessairement. Outre l'existence d'un VAD, le gestionnaire de mémoire évalue Reserve ou Commit, les attributs de protection lecture/écriture/exécution, les pages de garde, l'état de la PTE, et d'autres critères. Si le défaut ne peut pas être résolu, il devient 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 logiciels. 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.