Lorsqu'un processus bifurque sa mémoire virtuelle ou résidente est-elle copiée?

12

La façon standard de créer de nouveaux processus sous Linux est que l'empreinte mémoire du processus parent soit copiée et que cela devienne l'environnement du processus enfant jusqu'à ce qu'il execvsoit appelé.

De quelle empreinte mémoire parlons-nous, virtuelle (ce que le processus a demandé) ou résidente (qu'est-ce qui est réellement utilisé)?

Motivation: J'ai un appareil avec un espace d'échange limité et une application avec une grande différence entre l'empreinte mémoire virtuelle et résidente. L'application ne peut pas bifurquer en raison d'un manque de mémoire et aimerait voir si essayer de réduire la taille de l'empreinte virtuelle serait utile.

TheMeaningfulEngineer
la source

Réponses:

12

Dans les systèmes modernes, aucune de la mémoire n'est réellement copiée simplement parce qu'un appel système fork est utilisé. Tout est marqué en lecture seule dans le tableau des pages de telle sorte que lors de la première tentative d'écriture d'un piège dans le code du noyau se produira. Ce n'est qu'une fois que le premier processus tente d'écrire que la copie se produit.

C'est ce qu'on appelle la copie sur écriture.

Cependant, il peut également être nécessaire de garder une trace de l'espace d'adressage engagé. Si aucune mémoire ou échange n'est disponible au moment où le noyau doit copier une page, il doit tuer un processus pour libérer de la mémoire. Ce n'est pas toujours souhaitable, il est donc possible de garder une trace de la quantité de mémoire dans laquelle le noyau s'est engagé.

Si le noyau s'engage à dépasser la mémoire + swap disponible, il peut donner un code d'erreur lors de la tentative d'appeler fork. Si suffisamment est disponible, le noyau s'engage à la taille virtuelle complète du parent pour les deux processus après le fork.

kasperd
la source
1
If enough is available the kernel will commit to the full virtual size of the parent for both processes after the fork.Oui merci. Cela signifie que la réduction de l'empreinte virtuelle du processus dans un environnement avec une mémoire limitée (RAM et swap) pourrait résoudre le problème de ne pas pouvoir effectuer de fork.
TheMeaningfulEngineer
1
@Alan Oui. Si forkéchoue avec un message d'erreur indiquant une mémoire insuffisante. Réduire ensuite l'utilisation de la mémoire virtuelle du processus avant de bifurquer pourrait aider.
kasperd
5

Ne vous inquiétez pas, cela fait une copie paresseuse (copie sur écriture). Les adresses de mémoire virtuelle des deux processus pointent initialement vers les mêmes pages, mais lorsque le processus forké essaie de le modifier, il crée en fait une copie physique de la page (à partir de ce moment, cette page réside à deux endroits dans votre RAM).

Attention, aucune des empreintes de mémoire signalées ne vous indique réellement la quantité de RAM que le processus utilise. En raison de l'échange, du partage de mémoire et d'autres problèmes avec la mémoire virtuelle, il est impossible de le savoir avec certitude. Certaines parties de l'espace mémoire sont des bibliothèques partagées (où les compter?), Certaines se réfèrent à de la mémoire non RAM (autres périphériques matériels), certaines sont actuellement permutées, d'autres ne sont pas encore copiées (copie sur écriture) et bientôt. Lis ça:

https://lwn.net/Articles/642202/

orion
la source
5

Il y a un réglage du noyau

/ proc / sys / vm / overcommit_memory

Citation d'un excellent article :

Since 2.5.30 the values are: 0 (default): as before: guess about how much  
overcommitment is reasonable, 1: never refuse any malloc(), 2: be precise 
about the overcommit - never commit a virtual address space larger than swap 
space plus a fraction overcommit_ratio of the physical memory. Here 
/proc/sys/vm/overcommit_ratio (by default 50) is another user-settable 
parameter. It is possible to set overcommit_ratio to values larger than 100. 
(See also Documentation/vm/overcommit-accounting.)

Cela s'applique aux fourches ainsi qu'aux malloc ordinaires. Autrement dit, si vous le définissez sur 0, fork sera copié lors de l'écriture. La copie lors de l'écriture signifie qu'une fois l'application terminée, les deux copies partageront les pages de mémoire en utilisant l'enfant ou l'original commence à changer de mémoire.

Dans la plupart des distributions, je sais que la surcharge est 0. Mais si vous la définissez sur 2, toutes les pages de mémoire seront entièrement sauvegardées par de la mémoire réelle et dans certains cas, sous une pression de mémoire élevée, seront plus stables, mais certains programmes (j'ai fait face à gitk) qui s'appuient sur les sur-engagements échoueront.

gena2x
la source