Linux ne fait pas de "permutation opportuniste" comme défini dans cette question.
Les références principales suivantes ne mentionnent pas du tout le concept :
- Comprendre le gestionnaire de mémoire virtuelle Linux. Un livre en ligne de Mel Gorman. Écrit en 2003, juste avant la sortie de Linux 2.6.0.
- Documentation/admin-guide/sysctl/vm.rst. Il s'agit de la documentation principale des paramètres ajustables de la gestion de la mémoire virtuelle Linux.
Plus précisément :
10.6 Démon de pageout (kswapd)
Historiquement
kswapd
utilisé pour se réveiller toutes les 10 secondes mais maintenant il n'est réveillé par l'allocateur de page physique que lorsque le nombre de pages libres dans une zone est atteint. [...] Sous une pression mémoire extrême, les processus feront le travail dekswapd
de manière synchrone. [...]kswapd
continue de libérer des pages jusqu'à ce que le filigrane pages_high soit atteint.
Sur la base de ce qui précède, nous ne nous attendons à aucun échange lorsque le nombre de pages gratuites est supérieur au "high watermark".
Deuxièmement, cela nous indique le but de kswapd
est de créer plus de pages gratuites.
Quand kswapd
écrit une page mémoire à échanger, il libère immédiatement la page mémoire. kswapd ne conserve pas de copie de la page échangée en mémoire .
Linux 2.6 utilise le "rmap" pour libérer la page. Sous Linux 2.4, l'histoire était plus complexe. Lorsqu'une page était partagée par plusieurs processus, kswapd n'était pas en mesure de la libérer immédiatement. C'est de l'histoire ancienne. Tous les articles liés concernent Linux 2.6 ou supérieur.
échange
Ce contrôle est utilisé pour définir à quel point le noyau permutera les pages de mémoire. Des valeurs plus élevées augmenteront l'agressivité, des valeurs plus faibles diminueront la quantité d'échange. Une valeur de 0 indique au noyau de ne pas lancer l'échange jusqu'à ce que le nombre de pages libres et sauvegardées par des fichiers est inférieur à la ligne des hautes eaux dans une zone.
Cette citation décrit un cas particulier :si vous configurez le swappiness
la valeur doit être 0
. Dans ce cas, nous ne devons en outre pas nous attendre à un échange tant que le nombre de pages de cache n'est pas tombé au niveau supérieur. En d'autres termes, le noyau essaiera de supprimer presque tout le cache de fichiers avant de commencer l'échange. (Cela pourrait entraîner des ralentissements massifs. Vous devez avoir un cache de fichiers ! Le cache de fichiers est utilisé pour contenir le code de tous vos programmes en cours d'exécution :-)
Que sont les filigranes ?
Les citations ci-dessus soulèvent la question :Quelle est la taille des réservations de mémoire "filigrane" sur mon système ? Réponse :sur un "petit" système, les filigranes de zone par défaut peuvent atteindre 3 % de la mémoire. Cela est dû au calcul du filigrane "min". Sur les systèmes plus grands, les filigranes seront une proportion plus faible, approchant 0,3 % de la mémoire.
Donc, si la question concerne un système avec plus de 10 % de mémoire libre, les détails exacts de cette logique de filigrane ne sont pas significatifs.
Les filigranes pour chaque "zone" individuelle sont affichés en /proc/zoneinfo
, comme documenté dans proc(5). Un extrait de mon zoneinfo :
Node 0, zone DMA32
pages free 304988
min 7250
low 9062
high 10874
spanned 1044480
present 888973
managed 872457
protection: (0, 0, 4424, 4424, 4424)
...
Node 0, zone Normal
pages free 11977
min 9611
low 12013
high 14415
spanned 1173504
present 1173504
managed 1134236
protection: (0, 0, 0, 0, 0)
Les "filigranes" actuels sont min
, low
, et high
. Si jamais un programme demande suffisamment de mémoire pour réduire free
en dessous de min
, le programme entre "récupération directe". Le programme est mis en attente pendant que le noyau libère de la mémoire.
Nous voulons éviter la récupération directe si possible. Donc si free
tomberait sous le low
filigrane, le noyau réveille kswapd
. kswapd
libère de la mémoire en permutant et/ou supprimant les caches, jusqu'à free
est supérieur à high
à nouveau.
Diplôme supplémentaire :kswapd
s'exécutera également pour protéger le montant total de lowmem_reserve, pour l'utilisation du noyau lowmem et DMA. Le lowmem_reserve par défaut est d'environ 1/256 des premiers 4 Go de RAM (zone DMA32), il est donc généralement d'environ 16 Mo.
Commit du code Linux
mm :redimensionne les filigranes kswapd proportionnellement à la mémoire
[...]
watermark_scale_factor :
Ce facteur contrôle l'agressivité de kswapd. Il définit la quantité de mémoire restante dans un nœud/système avant que kswapd ne soit réveillé et la quantité de mémoire devant être libérée avant que kswapd ne se remette en veille.
L'unité est en fractions de 10 000. La valeur par défaut de 10 signifie que les distances entre les filigranes sont de 0,1 % de la mémoire disponible dans le nœud/système. La valeur maximale est 1 000, soit 10 % de la mémoire.
Un taux élevé de threads entrant dans la récupération directe (allocstall) ou kswapd allant dormir prématurément (kswapd_low_wmark_hit_quickly) peut indiquer que le nombre de pages libres que kswapd maintient pour des raisons de latence est trop petit pour les rafales d'allocation se produisant dans le système. Ce bouton peut ensuite être utilisé pour ajuster l'agressivité de kswapd en conséquence.
proc :meminfo :estime la mémoire disponible de manière plus prudente
Le
MemAvailable
article en/proc/meminfo
est de donner aux utilisateurs une indication de la quantité de mémoire pouvant être allouée sans provoquer d'échange, de sorte qu'il exclut les marques d'eau basses des zones comme indisponibles pour l'espace utilisateur.Cependant, pour une allocation d'espace utilisateur,
kswapd
sera en fait récupéré jusqu'à ce que les pages libres atteignent une combinaison du filigrane élevé et de la protection lowmem de l'allocateur de pages qui conserve également une certaine quantité de mémoire DMA et DMA32 de l'espace utilisateur.Soustrayez le montant total que nous savons être indisponible pour l'espace utilisateur du nombre de pages gratuites lors du calcul de MemAvailable.
Code Linux
On prétend parfois que changer swappiness
à 0
désactivera efficacement "l'échange opportuniste". Cela offre une piste d'investigation intéressante. S'il y a quelque chose appelé "échange opportuniste", et qu'il peut être réglé par swappiness, alors nous pourrions le rechercher en trouvant toutes les chaînes d'appel qui lisent vm_swappiness
. Notez que nous pouvons réduire notre espace de recherche en supposant CONFIG_MEMCG
n'est pas défini (c'est-à-dire que les "groupes de contrôle de mémoire" sont désactivés). La chaîne d'appel va :
- vm_swappiness
- mem_cgroup_swappiness
- get_scan_count
- shrink_node_memcg
- shrink_node
shrink_node_memcg
est commenté "Il s'agit d'une page de base par nœud plus libre. Utilisé à la fois par kswapd et la récupération directe". C'est à dire. cette fonction augmente le nombre de libres pages. Il n'essaie pas de dupliquer des pages pour les échanger afin qu'elles puissent être libérées beaucoup plus tard. Mais même si nous ne tenons pas compte de cela :
La chaîne ci-dessus est appelée à partir de trois fonctions différentes, illustrées ci-dessous. Comme prévu, nous pouvons diviser les sites d'appel en récupération directe vs. kswapd. Cela n'aurait pas de sens d'effectuer un "échange opportuniste" en récupération directe.
/* * This is the direct reclaim path, for page-allocating processes. We only * try to reclaim pages from zones which will satisfy the caller's allocation * request. * * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. */ static void shrink_zones
* kswapd shrinks a node of pages that are at or below the highest usable * zone that is currently unbalanced. * * Returns true if kswapd scanned at least the requested number of pages to * reclaim or if the lack of progress was due to pages under writeback. * This is used to determine if the scanning priority needs to be raised. */ static bool kswapd_shrink_node
* For kswapd, balance_pgdat() will reclaim pages across a node from zones * that are eligible for use by the caller until at least one zone is * balanced. * * Returns the order kswapd finished reclaiming at. * * kswapd scans the zones in the highmem->normal->dma direction. It skips * zones which have free_pages > high_wmark_pages(zone), but once a zone is * found to have free_pages <= high_wmark_pages(zone), any page in that zone * or lower is eligible for reclaim until at least one usable zone is * balanced. */ static int balance_pgdat
Donc, on peut supposer que l'affirmation est que kswapd est réveillé d'une manière ou d'une autre, même lorsque toutes les allocations de mémoire sont satisfaites immédiatement à partir de la mémoire libre. J'ai regardé à travers les utilisations de wake_up_interruptible(&pgdat->kswapd_wait)
, et je ne vois aucun réveil comme celui-ci.
Non, il n'y a pas d'échange opportuniste sous Linux. J'ai passé un certain temps à étudier le problème et toutes les sources (manuels, e-mails sur les listes de diffusion des développeurs du noyau, code source Linux et commentaires de validation, et quelques échanges sur Twitter avec Mel Gorman) me disent la même chose :Linux ne récupère que mémoire en réponse à une certaine forme de pression sur la mémoire (à l'exception évidente de l'hibernation).
Toutes les idées fausses populaires sur le sujet proviennent probablement du simple fait que Linux ne peut pas se permettre d'attendre le dernier octet de mémoire libre avant de commencer à échanger. Il a besoin d'une sorte de coussin pour le protéger des formes extrêmes d'épuisement de la mémoire, et certains réglages peuvent affecter la taille de ce coussin (par exemple, vm.min_free_kbytes
). Mais ce n'est pas la même chose que « troquer parce qu'il n'y a rien de mieux à faire ».
Malheureusement, l'algorithme de récupération de cadre de page est devenu beaucoup plus complexe par rapport à 2.6 (lorsqu'il a été décrit en détail dans le livre de Mel Gorman), mais l'idée de base est plus ou moins la même :la récupération de page est déclenchée par des échecs d'allocation, qui soit réveille kswapd
ou essayez de libérer des pages de manière synchrone (en fonction de la pression de la mémoire, des drapeaux d'allocation et d'autres facteurs).
La raison la plus évidente pour laquelle les allocations de pages peuvent commencer à échouer avec suffisamment de mémoire libre restante est qu'elles peuvent demander une mémoire contiguë alors qu'en réalité la mémoire peut être trop fragmentée pour satisfaire la demande. Historiquement, les développeurs du noyau Linux se sont donné beaucoup de mal pour éviter le besoin d'allocations contiguës. Néanmoins, certains pilotes de périphériques l'exigent toujours - soit parce qu'ils ne peuvent pas effectuer d'E / S de mémoire multipage (DMA par dispersion), soit parce que cela peut simplement être un codage bâclé par les développeurs de pilotes. L'avènement des Transparent Huge Pages (THP) a fourni une autre raison d'allouer de la mémoire en blocs physiquement contigus.
Le compactage de zone, qui a été introduit à peu près au même moment, est censé aider à résoudre le problème de fragmentation de la mémoire, mais il ne produit pas toujours l'effet escompté.
Il existe différents vmscan
des points de trace qui peuvent aider à comprendre ce qui se passe exactement dans votre cas spécifique ; il est toujours plus facile de trouver ce dont vous avez besoin dans le code du noyau Linux lorsque vous avez des piles d'appels spécifiques, plutôt que de simplement analyser tout ce qui semble pertinent à distance.