web-dev-qa-db-fra.com

Windows indique que RAM s'est épuisé alors qu'il reste 4 Go de mémoire physique disponible

Screenshot of System Information from Process Explorer

Cette information système provient de Process Explorer. Il reste encore de la mémoire physique, mais le système n'affiche presque plus RAM.

Le Gestionnaire des tâches indique également qu'environ 74% du total RAM est utilisé.

Depuis l’installation de Windows 8.1, l’ordinateur disposait de 4 + 8 = 12 Go de RAM. Je l'ai mis à niveau en changeant les 4 Go en un module de 8 Go. Est-ce que cela pourrait être le problème? Ou ce comportement est-il normal et je viens de mal comprendre le sens de la mémoire physique disponible?

23
user471487

Réponse courte

La fenêtre contextuelle "Mémoire insuffisante" indique que vous êtes à court de limite de mémoire privée privée, type de mémoire virtuelle. Non pas que vous manquiez de RAM (mémoire physique). Peu importe combien disponible RAM vous avez. Avoir beaucoup de Available RAM ne vous permet pas de dépasser la limite de validation. La limite de validation est la somme de votre total RAM (en cours d'utilisation ou non!) Plus la taille actuelle du fichier d'échange.

Inversement, ce qui "utilise" la limite de validation (qui consiste principalement à créer un espace d'adressage virtuel privé de processus) n'utilise pas nécessairement de RAM! Mais le système d'exploitation ne permettra pas sa création à moins de savoir qu'il existe un emplacement pour le stocker s'il le souhaite. Vous pouvez donc respecter la limite de validation sans utiliser toute votre RAM, ni même la majeure partie de votre RAM.

C'est pourquoi vous ne devriez pas courir sans fichier d'échange. Notez que le fichier d'échange peut ne jamais être écrit! Mais cela vous permettra néanmoins d'éviter les erreurs "manque de mémoire" et "insuffisance de mémoire".

Réponse intermédiaire

En réalité, Windows ne dispose pas d'un message d'erreur indiquant que la mémoire vive est insuffisante. Ce qui vous manque, c'est la "limite de commit".

Le graphe "Système" de cette version de Process Explorer est mal nommé. Il devrait être étiqueté "commit charge". (Dans la version que j'ai, il s'intitule "System commit". Mieux, mais pas toujours totalement cohérent.) Quoi qu'il en soit, la hauteur "actuelle" du graphique indique ce qui apparaît plus bas dans la section de texte sous "Commit Charge" - " Current ", et la hauteur maximale du graphique représente" Commit Charge "-" Limit ".

"Commit Charge" fait référence à un espace d'adressage virtuel sauvegardé par le fichier d'échange (si vous en avez un). En d'autres termes, s'il ne tient pas entièrement dans la RAM, le reste est transféré dans le fichier d'échange. (Il existe d'autres types de vas qui sont sauvegardés par d'autres fichiers - c'est ce qu'on appelle un vasque "mappé" - ou qui doivent rester dans RAM tout le temps; ce dernier est appelé "non pageable".) Le "commit limite "est le maximum que la" commission de validation "peut être. Il est égal à votre taille RAM plus la taille du fichier d'échange.

Vous n'avez apparemment aucun fichier d'échange (je peux le savoir car votre limite de validation est égale à votre taille RAM), la limite de validation est donc simplement la taille RAM.

Apparemment, divers programmes + le système d'exploitation ont utilisé presque tout le commit possible.

Cela n'a rien à voir directement avec combien de RAM est libre ou disponible. Oui, vous avez environ 4,5 Go RAM disponibles. Cela ne signifie pas que vous pouvez dépasser la limite de validation. La mémoire validée n'utilise pas nécessairement RAM et n'est pas limitée par la quantité de RAM disponible.

Vous devez réactiver le fichier d'échange - en utilisant ceci, je suggère un fichier d'échange de 16 Go, car vous ne voulez pas forcer le système d'exploitation à conserver autant de ce contenu dans la RAM, et le fichier d'échange fonctionnera mieux s'il fonctionne correctement. a beaucoup d'espace libre - ou bien ajoutez plus de RAM. Beaucoup plus. Pour obtenir de bonnes performances, vous devez disposer de suffisamment d'espace dans RAM pour le code et d'autres éléments non sauvegardés par le fichier d'échange (mais pouvant être transférés vers d'autres fichiers).

Réponse très longue

(mais toujours beaucoup plus court que le chapitre sur la gestion de la mémoire de Windows en interne ...)

Supposons qu'un programme alloue 100 Mo de mémoire virtuelle privée de processus. Ceci est fait avec un appel VirtualAlloc avec l'option "commit". Cela se traduira par une augmentation de 100 Mo de la "charge de validation". Mais cette "allocation" n'utilise pas réellement de RAM! RAM est uniquement utilisé lorsque certains accès à cet espace d'adressage virtuel récemment engagé sont effectués pour la première fois.

Comment le RAM est finalement utilisé

(si cela arrive)

L’accès initial à l’espace nouvellement engagé correspondrait presque toujours à une écriture en mémoire (la lecture de fichiers privés nouvellement alloués avant d’écrire est presque toujours une erreur de programmation puisque son contenu initial n’est pas défini à proprement parler). Mais en lecture ou en écriture, le résultat, la première fois que vous touchez une page de v.a.s. récemment allouée, est un défaut de page . Bien que le mot "faute" sonne mal, les fautes de page sont un événement complètement attendu et même requis dans un système d'exploitation à mémoire virtuelle.

En réponse à ce type particulier d'erreur de page, le pageur (composant du gestionnaire de mémoire du système d'exploitation, que je qualifierai parfois de "Mm") va:

  1. allouer une page physique de RAM (idéalement à partir de la liste des pages zéro, mais dans tous les cas, elle provient de ce que Windows appelle "disponible": liste des pages zéro, libre ou en attente, dans cet ordre de préférence )
  2. remplissez une entrée de table de pages pour associer la page physique à la page virtuelle; et enfin
  3. rejeter l'exception de faute de page.

Après quoi le code qui a fait la référence en mémoire ré-exécutera l'instruction qui a provoqué l'erreur de page, et cette fois la référence réussira.

Nous disons que la page a été "introduite par erreur" dans l'ensemble de processus et dans la RAM. Dans le Gestionnaire des tâches, cela apparaîtra comme une augmentation d'une page (4 Ko) du "groupe de travail privé" du processus. Et une réduction d'une page de la mémoire physique disponible. (Ce dernier peut être difficile à remarquer sur une machine occupée.)

Note 1: Cette erreur de page n'impliquait rien de lu sur le disque. Une page de mémoire virtuelle engagée jamais utilisée auparavant ne commence sa vie sur le disque; il n'a pas de place sur le disque pour le lire à partir de . Il est simplement "matérialisé" dans une page de RAM précédemment disponible. Statistiquement, en fait, la plupart des erreurs de page sont résolues dans la RAM, soit aux pages partagées qui se trouvent déjà dans RAM pour d’autres processus, soit aux caches de page - les listes en attente ou modifiées, ou en tant que "demande zéro" des pages comme celle-ci.

Note 2: Cela ne prend qu'une page, 4096 octets, à partir de "Disponible". Un espace d'adressage engagé jamais touché auparavant est normalement créé - défectueux - juste une page à la fois, chaque page étant "touchée" pour la première fois. Il n'y aurait aucune amélioration, aucun avantage à faire plus à la fois; cela prendrait juste n fois plus longtemps. En revanche, lorsque les pages doivent être lues à partir du disque, une certaine quantité de "readahead" est tentée car la grande majorité du temps lu sur le disque correspond à un temps système par opération, et non au transfert de données proprement dit. Le montant "engagé" reste à 100 Mo; le fait qu'une ou plusieurs pages aient été mises en défaut ne réduit pas la charge de validation.

Note 3: Supposons que nous ayons 4 Go de RAM "disponible". Cela signifie que nous pourrions faire référence à la mémoire réservée déjà allouée mais jamais auparavant référencée environ un million de fois (4 Go/4096) avant de manquer de mémoire vive. À ce stade, si nous avons un fichier d'échange comme le souhaitent David Cutler et Lou Perazzoli, certaines des pages référencées depuis le plus ancien dans RAM seraient enregistrées sur le disque, puis rendues disponibles pour une résolution plus récente. défauts de page. (En réalité, le système d'exploitation initie RAM des méthodes de récupération telles que le "réglage du groupe de travail" plutôt avant cela, et les écritures réelles dans le fichier d'échange sont mises en cache et mises en lot sur la liste de pages modifiée pour plus d'efficacité, et ...) Rien de tout cela n’affecterait le compte "commis". Cela concerne toutefois la "limite de validation". S'il n'y a pas de place pour toute la mémoire "dédiée" dans la RAM, l'excédent peut être conservé dans le fichier d'échange. Ainsi, la taille du fichier d'échange contribue à la "limite de validation".

Et ça continue ...

Mais supposons que nous n’ayons pas fait ces millions de références supplémentaires et qu’il reste encore environ 4 Go de pages "disponibles". Supposons maintenant que le même processus - ou un autre, peu importe - effectue un autre VirtualAlloc, cette fois-ci de 200 Mo engagés. Encore une fois, ces 200 Mo sont ajoutés aux frais de validation et ne suppriment pas les RAM disponibles. Simplement VirtualAlloc'ating, l’espace adresse n’utilise pas la quantité correspondante de RAM, et le faible "disponible" RAM ne limite pas la quantité d’espace adresse que vous pouvez utiliser avec VirtualAlloc (ni le haut niveau de disponibilité RAM l'augmenter).

(Eh bien, d'accord ... il y a un peu de frais généraux, ce qui équivaut à une page (paginable!) Utilisée pour un tableau de pages par tranche de 2 Mo (4 Mo si vous utilisez un système x86 non-PAE) de espace d'adressage virtuel alloué, et il existe un "descripteur d'adresse virtuelle" de quelques dizaines d'octets pour chaque plage allouée pratiquement contigu.)

De cette façon, c'est possible - et commun! - utiliser beaucoup de "frais de validation" en n'utilisant que de petites quantités de RAM.

Donc, si "valider" l'espace d'adressage virtuel n'utilise pas de mémoire vive, pourquoi faut-il qu'il y ait une limite?

Parce que la "commission de validation" représente effectivement une utilisation potentielle future de l'espace de stockage. "Limite de validation" représente la quantité totale de stockage (RAM + espace fichier) disponible pour contenir de telles allocations, si jamais elles étaient référencées et devaient ensuite être stockées quelque part.

Lorsque Mm approuve une requête VirtualAlloc, il est prometteur - "s'engager" - que tous les accès en mémoire ultérieurs à la zone allouée aboutiront; ils peuvent entraîner des défauts de page, mais ces derniers pourront tous être résolus, car il existe un IS espace de stockage suffisant pour conserver le contenu de toutes ces pages, que ce soit dans RAM ou fichier de page. Mm le sait car il sait combien d’espace de stockage il existe (la limite de validation) et combien a déjà été "commis" (la commission de validation actuelle).

(Mais toutes ces pages n’ont pas encore nécessairement été consultées, il n’existe donc pas forcément d’espace de stockage correspondant au montant engagé, à un moment donné.)

Alors ... Qu'en est-il "système est à court de mémoire"?

Si vous essayez de VirtualAlloc et que les frais de validation actuels ainsi que la taille d’allocation demandée dépassent la limite de validation ET que le système d’exploitation ne peut pas développer le fichier d'échange de manière à augmenter la limite de validation ... vous obtenez le message "mémoire insuffisante". et le processus voit l'appel de VirtualAlloc FAIL. La plupart des programmes lèveront leurs mains et mourront à ce moment-là. Certains poursuivront aveuglément, en supposant que l'appel réussisse, et échoueront plus tard lorsqu'ils tenteront de faire référence à la région qu'ils pensaient avoir attribuée.

Encore une fois (désolé pour la répétition): peu importe combien vous avez de Available RAM. Le système d'exploitation a promis que l'espace RAM ou le fichier d'échange sera disponible en cas de besoin, mais cette promesse ne soustrait pas "Disponible". Available RAM est uniquement utilisé par v.m. quand il est référencé pour la première fois, ce qui explique son "défaut dans" ... c'est-à-dire réalisé dans la mémoire physique. Et commettre simplement (= allouer) de la mémoire virtuelle ne fait pas cela. Il ne prend que de l'espace d'adressage virtuel libre et en fait un espace d'adressage virtuel utilisable.

Mais dans le cas "insuffisante de mémoire", il y a eu une demande d'allocation pour la mémoire validée, et le système d'exploitation a ajouté la commission de validation actuelle à la taille de cette nouvelle requête ... et a constaté que le total est plus que la limite de commit. Donc, si le système d'exploitation approuvait ce nouveau, et tout cet espace était ensuite référencé, il n'y aurait aucun emplacement réel (RAM + fichier d'échange) pour tout stocker.

Le système d'exploitation ne permettra pas cela. Il ne permettra plus de v.a.s. être alloué plus que de la place pour le conserver dans le pire des cas - même si tout est "fautif". C'est le but de la "limite de commit".

Je vous le dis trois fois, je vous le dis trois fois, je vous le répète trois fois: La quantité de "Disponible" RAM n'a pas d'importance. Le fait que l'espace virtuel dédié n'utilise pas encore tout cet espace de stockage n'a pas d'importance. Windows ne peut pas "commettre" sur l'allocation virtuelle à moins qu'il ne soit "possible" d'avoir une faute dans l'avenir.

Notez qu'il existe un autre type de v.a.s. appelé "mappé", principalement utilisé pour le code et l'accès aux fichiers de données volumineux, mais il n'est pas facturé pour "commettre la charge" et n'est pas limité par la "limite de validation". En effet, il possède sa propre zone de stockage, les fichiers "mappés" sur celle-ci. La seule limite sur "mappé" v.a.s. est la quantité d'espace disque que vous avez pour les fichiers mappés et la quantité de v.a.s. libre dans votre processus pour les mapper dans.

Mais quand je regarde le système, je ne suis pas encore à la limite de commit?

Il s’agit essentiellement d’un problème de mesure et de tenue de registres. Vous examinez le système après qu'un appel VirtualAlloc a déjà été tenté et a échoué.

Supposons qu'il ne reste que 500 Mo de limite de validation et que certains programmes ont essayé de créer VirtualAlloc 600 Mo. La tentative échoue. Ensuite, vous regardez le système et dites "Quoi? Il reste encore 500 Mo!" En fait, il pourrait en rester encore beaucoup plus, car le processus en question a probablement complètement disparu à ce stade, de sorte que TOUT sa mémoire dédiée précédemment allouée a été libérée.

Le problème est que vous ne pouvez pas revenir en arrière et voir quelle était la charge de validation au moment de la tentative d'allocation. Et vous ne savez pas non plus combien d’espace a été utilisé pour cette tentative. Vous ne pouvez donc pas voir avec certitude pourquoi la tentative a échoué ou combien de "limite de validation" aurait été nécessaire pour que cela fonctionne.

J'ai vu "le système est en train de manquer en mémoire". Qu'est-ce que c'est?

Si, dans le cas ci-dessus, le système d'exploitation PEUT développer le fichier d'échange (c'est-à-dire que vous le laissez sur le paramètre par défaut "géré par le système" ou que vous le gérez mais que vous définissez le maximum sur une valeur supérieure à celle initiale, ET qu'il y a suffisamment d'espace disque disponible) une telle extension augmente suffisamment la limite de validation pour laisser l'appel VirtualAlloc aboutir, puis ... le fichier Mm développe le fichier d'échange et l'appel VirtualAlloc aboutit.

Et c'est à ce moment-là que vous voyez "le système fonctionne à faible mémoire". C'est un avertissement précoce que si les choses continuent sans atténuation, vous verrez probablement bientôt un avertissement "mémoire insuffisante". Il est temps de fermer certaines applications. Je commencerais par les fenêtres de votre navigateur.

Et vous pensez que c'est une bonne chose? L'expansion du fichier d'échange est diabolique !!!

Non ce n'est pas. Vous voyez, le système d'exploitation ne "développe" pas vraiment le fichier existant. Il alloue juste une nouvelle mesure. L'effet ressemble beaucoup à tout autre fichier non contigu. L'ancien contenu du fichier d'échange reste exactement là où il se trouve; ils ne doivent pas être copiés vers un nouvel endroit ou quelque chose comme ça. Comme la plupart des fichiers d'échange IO sont relativement petits, comparés à la taille du fichier d'échange, les chances qu'un transfert donné franchisse une limite d'étendue sont vraiment rares, de sorte que la fragmentation ne fait pas beaucoup mal, sauf si elle est vraiment excessive.

Enfin, une fois que tous les processus qui ont "engagé" de l’espace dans l’extension se sont arrêtés (à l’arrêt du système d’exploitation sinon plus tôt), les extensions sont libérées en mode silencieux et le fichier d'échange retrouvera sa taille et son allocation précédentes - s'il était contigu auparavant, il est si encore.

Autoriser l'expansion du fichier d'échange agit donc comme un filet de sécurité totalement gratuit: si vous le permettez mais que le système n'en a jamais besoin, le système ne "développera pas et ne réduira pas en permanence le fichier d'échange" comme on le prétend souvent, de sorte qu'il ne coûtera rien . Et si vous en avez besoin, cela vous évitera de tomber en panne avec une erreur "manque de mémoire virtuelle".

Mais mais mais ...

J'ai lu sur des dizaines de sites Web que si vous autorisez l'expansion du fichier d'échange, Windows développera et contractera constamment le fichier d'échange, ce qui entraînera une fragmentation du fichier d'échange jusqu'à la défragmentation.

Ils ont juste tort.

Si vous n'avez jamais vu la fenêtre contextuelle "manque de mémoire" (ou, dans les versions précédentes, "manque de mémoire virtuelle"), le système d'exploitation n'a jamais développé votre fichier d'échange.

Si vous voyez cette fenêtre contextuelle, cela vous indique que la taille initiale du fichier d'échange est trop petite. (J'aime utiliser environ 4 fois l'utilisation maximale observée; en d'autres termes, le compteur de performances "% du fichier d'utilisation maximum du fichier de pages" doit être inférieur à 25%. Raison: l'espace de fichier d'échange est géré comme tout autre segment et fonctionne mieux avec beaucoup d'espace libre. jouer.)

Mais pourquoi ne font-ils pas ...

On pourrait soutenir que le système d'exploitation devrait simplement laisser l'allocation se produire, puis laisser les références échouer s'il n'y a pas de RAM disponible pour résoudre les défauts de page. En d'autres termes, ci-dessus où nous avons décrit le fonctionnement de la défaillance de page initiale, que se passe-t-il si "allouer une page physique disponible de RAM" (étape 1) ne peut pas être effectué car il n'y en avait aucune, et il n’y avait plus d’endroit où puiser quoi que ce soit pour en rendre disponible

Ensuite, le pager serait incapable de résoudre le problème de page. Il devrait permettre à l'exception (la faute de page) d'être renvoyée au thread défaillant, probablement remplacée par un autre code d'exception.

La philosophie de conception est que VirtualAlloc renverra zéro (techniquement un pointeur NULL) au lieu d'une adresse si vous manquez de limite de validation, et il est tout à fait raisonnable de s'attendre à ce que le programmeur sache qu'un appel VirtualAlloc peut échouer. Les programmeurs sont donc censés vérifier ce cas et faire quelque chose de raisonnable en réponse (par exemple, vous permettre de sauvegarder votre travail jusqu’à ce moment-là, puis de terminer le programme "en douceur"). (Programmeurs: Vous vérifiez si un pointeur NULL est renvoyé par malloc, new, etc., oui? Alors pourquoi ne le feriez-vous pas?)

Mais les programmeurs ne doivent pas s’attendre à ce qu’une simple référence en mémoire, telle que

i = 0;             // initialize loop counter

peut échouer - pas s'il se trouve dans une région d'espace d'adressage engagé avec succès. (Ou un espace d'adressage mappé, d'ailleurs). Mais c'est ce qui pourrait arriver si la philosophie "autoriser l'allocation trop engagée, laisser la référence de la mémoire échouer" était suivie.

Malheureusement, une référence de mémoire comme celle de la ligne de code ci-dessus n'a pas de moyen commode de retourner un mauvais statut! Ils sont simplement supposés travailler , tout comme les additions et les soustractions. Le seul moyen de signaler de tels échecs serait d'exceptions. Donc, pour les gérer, le programmeur devrait envelopper tout le programme dans un gestionnaire d'exceptions. (essayer ... attraper et tout ça.)

Cela peut être fait ... Mais il serait difficile pour le gestionnaire de savoir comment "agir correctement" en réponse à ces exceptions, car il pourrait y avoir de très nombreux points dans le code où ils pourraient survenir. (Plus précisément, elles pourraient apparaître à chaque référence en mémoire à la mémoire VirtualAlloc'd, à la mémoire allouée avec malloc ou new ... et à toutes les variables locales également, car la pile est VirtualAlloc ' d aussi.)

En bref, faire échouer le programme avec élégance dans ces cas serait très difficile.

En revanche, il est assez facile de rechercher un retour de pointeur NULL de VirtualAlloc (ou malloc ou nouveau, d'ailleurs, bien qu'ils ne soient pas exactement la même chose), puis de faire quelque chose de raisonnable ... comme ne pas essayer d'aller et faites ce que le programme avait besoin de cet espace virtuel. Et peut-être demander à l'utilisateur s'il souhaite sauvegarder son travail jusqu'à présent, le cas échéant. (Certes, beaucoup trop d'applications ne s'en donnent pas la peine.)

Autres utilisateurs de commit

Incidemment, la "limite de validation" n'est pas réduite par les différentes allocations du système d'exploitation, telles que le pool paginé et non paginé, la liste des PFN, etc. ceux-ci sont juste chargés de commettre une charge comme ils se produisent. Ni la charge ni la limite de validation ne sont affectées par la RAM vidéo, ni même par la taille de la vidéo RAM "fenêtre".

Testez-le vous-même

Vous pouvez faire la démonstration de tout cela avec l'outil testlimit du site SysInternals. L'option -m allouera un espace d'adressage engagé mais ne le "touchera" pas et ne causera donc pas d'allocation de RAM. Alors que l'option -d allouera et référencera également les pages, ce qui entraînera une augmentation des frais de validation et une diminution de la quantité disponible RAM.

Références

Windows Internals de Russinovich, Solomon et Ionescu. Il existe même des démonstrations vous permettant de prouver tous ces points à l'aide de l'outil testlimit. Cependant, je dois vous avertir que si vous pensez que cela a été long, soyez averti: le seul chapitre de Mm fait 200 pages; ce qui précède est une version extrêmement simplifiée. (Consultez également la section "Remerciements" de l'introduction.)

Voir aussi la documentation MSDN VirtualAlloc

63
Jamie Hanrahan