Linux peut-il «manquer de RAM»?

20

J'ai vu plusieurs publications sur le Web de personnes se plaignant apparemment d'un VPS hébergé tuant de manière inattendue des processus parce qu'ils utilisaient trop de RAM.

Comment est-ce possible? Je pensais que tous les systèmes d'exploitation modernes fournissent une «RAM infinie» en utilisant simplement un échange de disque pour tout ce qui va sur la RAM physique. Est-ce correct?

Que peut-il se passer si un processus est "tué en raison d'une faible RAM"?

le miroir
la source
12
Aucun OS n'a de RAM infinie . En plus des puces RAM physiques de la machine, les systèmes d'exploitation peuvent - généralement, en option - utiliser un soi-disant «fichier d'échange» qui se trouve sur le disque. Lorsqu'un ordinateur a besoin de plus de mémoire qu'il n'en a dans les bâtons de RAM, il échange des éléments dans le fichier d'échange. Mais à mesure que le fichier d'échange atteint sa capacité - soit parce que vous définissez une taille maximale (typique) soit parce que le disque se remplit - vous manquez de mémoire virtuelle.
John Dibling
@JohnDibling; y a-t-il une raison pour laquelle on voudrait limiter la taille du swap autrement que pour économiser de l'espace disque pour le système de fichiers? En d'autres termes, si j'ai un disque de 20 Go et seulement 1 Go de fichiers, y a-t-il une raison pour ne pas définir ma taille de swap sur 19 Go?
themirror
1
Pour simplifier les choses, je dirais que les deux raisons de limiter la taille des swaps sont 1) pour réduire la consommation de disque et 2) pour augmenter les performances. Ce dernier peut être plus vrai sous Windows que / * NIX, mais là encore, si vous utilisez l'espace de swap sur votre disque, vos performances sont dégradées. L'accès au disque est soit plus lent que la RAM, soit beaucoup plus lent que la RAM, selon le système.
John Dibling
9
Le swap n'est pas de la RAM . en.wikipedia.org/wiki/Random-access_memory La quantité de RAM dans votre système est la quantité de RAM dans votre système - période. Ce n'est pas un volume ambigu ou dynamique. C'est absolument fixe. La «mémoire» est un concept plus ambigu, mais la distinction entre la RAM et d'autres formes de stockage est, comme le souligne terdon (+1), assez significative. L'échange de disque ne peut pas remplacer les performances de la RAM par de nombreux ordres de grandeur . Un système qui dépend excessivement du swap est au mieux temporaire et en général: des ordures.
goldilocks
1
L'espace disque est donc infini maintenant?
Kaz

Réponses:

41

Que peut-il se passer si un processus est "tué en raison d'une faible RAM"?

On dit parfois que Linux par défaut ne refuse jamais les demandes de mémoire supplémentaire à partir du code d'application - par exemple malloc(). 1 Ce n'est pas vrai en fait; la valeur par défaut utilise une heuristique selon laquelle

Les surcharges évidentes d'espace d'adressage sont refusées. Utilisé pour un système typique. Il garantit qu'une allocation sérieusement sauvage échoue tout en permettant un sur-engagement pour réduire l'utilisation du swap.

De [linux_src]/Documentation/vm/overcommit-accounting(toutes les citations proviennent de l'arbre 3.11). Ce qui compte exactement comme une «allocation sérieusement sauvage» n'est pas rendu explicite, il nous faudrait donc passer par la source pour déterminer les détails. Nous pourrions également utiliser la méthode expérimentale de la note de bas de page 2 (ci-dessous) pour essayer d'obtenir une certaine réflexion de l'heuristique - sur cette base, mon observation empirique initiale est que dans des circonstances idéales (== le système est inactif), si vous ne le faites pas '' Si vous avez un swap, vous serez autorisé à allouer environ la moitié de votre RAM, et si vous avez un swap, vous obtiendrez environ la moitié de votre RAM plus la totalité de votre swap. C'est plus ou moins par processus (mais notez que cette limite est dynamique et susceptible de changer en raison de l'état, voir quelques observations dans la note 5).

La moitié de votre RAM plus swap est explicitement la valeur par défaut pour le champ "CommitLimit" dans /proc/meminfo. Voici ce que cela signifie - et notez que cela n'a rien à voir avec la limite qui vient d'être discutée (à partir de [src]/Documentation/filesystems/proc.txt):

CommitLimit: basé sur le ratio de sur-engagement ('vm.overcommit_ratio'), il s'agit de la quantité totale de mémoire actuellement disponible pour être allouée sur le système. Cette limite n'est respectée que si la comptabilité stricte de sur-validation est activée (mode 2 dans 'vm.overcommit_memory'). Le CommitLimit est calculé avec la formule suivante: CommitLimit = ('vm.overcommit_ratio' * RAM physique) + Swap Par exemple, sur un système avec 1G de RAM physique et 7G de swap avec un 'vm.overcommit_ratio' de 30, cela donnerait un CommitLimit de 7.3G.

Le document de comptabilité de surengagement précédemment cité indique que la valeur par défaut vm.overcommit_ratioest 50. Donc, si vous sysctl vm.overcommit_memory=2, vous pouvez ensuite ajuster vm.covercommit_ratio (avec sysctl) et voir les conséquences. 3 Le mode par défaut, lorsqu'il CommitLimitn'est pas appliqué et que «les surcharges évidentes d'espace d'adressage sont refusées», est lorsque vm.overcommit_memory=0.

Bien que la stratégie par défaut ait une limite heuristique par processus empêchant «l'allocation sérieusement sauvage», elle laisse le système dans son ensemble libre de devenir sérieusement sauvage, en termes d'allocation. 4 Cela signifie qu'à un moment donné, il peut manquer de mémoire et devoir déclarer faillite à certains processus via le tueur OOM .

Qu'est-ce que le tueur OOM tue? Pas nécessairement le processus qui demandait de la mémoire quand il n'y en avait pas, car ce n'est pas nécessairement le processus vraiment coupable, et plus important encore, pas nécessairement celui qui éliminera le plus rapidement le système du problème dans lequel il se trouve.

Ceci est cité à partir d' ici qui cite probablement une source 2.6.x:

/*
 * oom_badness - calculate a numeric value for how bad this task has been
 *
 * The formula used is relatively simple and documented inline in the
 * function. The main rationale is that we want to select a good task
 * to kill when we run out of memory.
 *
 * Good in this context means that:
 * 1) we lose the minimum amount of work done
 * 2) we recover a large amount of memory
 * 3) we don't kill anything innocent of eating tons of memory
 * 4) we want to kill the minimum amount of processes (one)
 * 5) we try to kill the process the user expects us to kill, this
 *    algorithm has been meticulously tuned to meet the principle
 *    of least surprise ... (be careful when you change it)
 */

Ce qui semble être une justification décente. Cependant, sans devenir médico-légal, le n ° 5 (qui est redondant du n ° 1) semble être une mise en œuvre difficile à vendre, et le n ° 3 est redondant du n ° 2. Il pourrait donc être judicieux de considérer cela comme réduit aux # 2/3 et # 4.

J'ai parcouru une source récente (3.11) et j'ai remarqué que ce commentaire avait changé entre-temps:

/**
 * oom_badness - heuristic function to determine which candidate task to kill
 *
 * The heuristic for determining which task to kill is made to be as simple and
 * predictable as possible.  The goal is to return the highest value for the
 * task consuming the most memory to avoid subsequent oom failures.
 */

Ceci est un peu plus explicitement à propos de # 2: "Le but est de [tuer] la tâche consommant le plus de mémoire pour éviter les échecs OOM ultérieurs", et par implication # 4 ( "nous voulons tuer le nombre minimum de processus ( un ) ) .

Si vous voulez voir le tueur OOM en action, voir la note de bas de page 5.


1 Une illusion dont Gilles m'a heureusement débarrassé, voir commentaires.


2 Voici un bit simple de C qui demande des morceaux de mémoire de plus en plus grands pour déterminer quand une demande de plus échouera:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define MB 1 << 20

int main (void) {
    uint64_t bytes = MB;
    void *p = malloc(bytes);
    while (p) {
        fprintf (stderr,
            "%lu kB allocated.\n",
            bytes / 1024
        );
        free(p);
        bytes += MB;
        p = malloc(bytes);
    }
    fprintf (stderr,
        "Failed at %lu kB.\n",
        bytes / 1024
    );
    return 0;
}            

Si vous ne connaissez pas C, vous pouvez le compiler gcc virtlimitcheck.c -o virtlimitcheck, puis l'exécuter ./virtlimitcheck. Il est complètement inoffensif, car le processus n'utilise aucun de l'espace qu'il demande - c'est-à-dire qu'il n'utilise jamais vraiment de RAM.

Sur un système 3.11 x86_64 avec un système de 4 Go et 6 Go de swap, j'ai échoué à ~ 7400000 ko; le nombre fluctue, donc peut-être que l'état est un facteur. C'est par hasard proche de l' CommitLimitentrée /proc/meminfo, mais la modification de ce via vm.overcommit_ratione fait aucune différence. Sur un système 3.6.11 32 bits ARM 448 Mo avec 64 Mo de swap, cependant, j'échoue à ~ 230 Mo. Ceci est intéressant car dans le premier cas, la quantité est presque le double de la quantité de RAM, alors que dans le second, elle est d'environ 1/4 - ce qui implique fortement la quantité de swap est un facteur. Cela a été confirmé en désactivant le swap sur le premier système, lorsque le seuil de défaillance est tombé à environ 1,95 Go, un rapport très similaire à la petite boîte ARM.

Mais est-ce vraiment par processus? Il semble être. Le programme court ci-dessous demande un morceau de mémoire défini par l'utilisateur, et s'il réussit, attend que vous frappiez retour - de cette façon, vous pouvez essayer plusieurs instances simultanées:

#include <stdio.h>
#include <stdlib.h>

#define MB 1 << 20

int main (int argc, const char *argv[]) {
    unsigned long int megabytes = strtoul(argv[1], NULL, 10);
    void *p = malloc(megabytes * MB);
    fprintf(stderr,"Allocating %lu MB...", megabytes);
    if (!p) fprintf(stderr,"fail.");
    else {
        fprintf(stderr,"success.");
        getchar();
        free(p);
    }
    return 0;
}

Attention, cependant, il ne s'agit pas strictement de la quantité de RAM et de swap quelle que soit l'utilisation - voir la note de bas de page 5 pour les observations sur les effets de l'état du système.


3 CommitLimit fait référence à la quantité d'espace d'adressage autorisée pour le système lorsque vm.overcommit_memory = 2. On peut supposer que le montant que vous pouvez allouer devrait être ce moins ce qui est déjà engagé, ce qui est apparemment le Committed_ASchamp.

Une expérience potentiellement intéressante démontrant cela consiste à ajouter #include <unistd.h>en haut de virtlimitcheck.c (voir référence 2), et fork()juste avant la while()boucle. Cela n'est pas garanti de fonctionner comme décrit ici sans une synchronisation fastidieuse, mais il y a de fortes chances que cela fonctionne, YMMV:

> sysctl vm.overcommit_memory=2
vm.overcommit_memory = 2
> cat /proc/meminfo | grep Commit
CommitLimit:     9231660 kB
Committed_AS:    3141440 kB
> ./virtlimitcheck 2&> tmp.txt
> cat tmp.txt | grep Failed
Failed at 3051520 kB.
Failed at 6099968 kB.

Cela a du sens - en regardant tmp.txt en détail, vous pouvez voir que les processus alternent leurs allocations de plus en plus grandes (c'est plus facile si vous jetez le pid dans la sortie) jusqu'à ce que l'un, évidemment, ait suffisamment revendiqué que l'autre échoue. Le gagnant est alors libre de tout récupérer jusqu'à CommitLimitmoins Committed_AS.


4 Il convient de mentionner, à ce stade, si vous ne comprenez pas déjà l'adressage virtuel et la pagination de la demande, que ce qui rend possible un engagement excessif, c'est que ce que le noyau alloue aux processus de l'espace utilisateur n'est pas du tout de la mémoire physique - c'est espace d'adressage virtuel . Par exemple, si un processus réserve 10 Mo pour quelque chose, il est présenté comme une séquence d'adresses (virtuelles), mais ces adresses ne correspondent pas encore à la mémoire physique. Lorsqu'une telle adresse est accessible, cela entraîne un défaut de pagepuis le noyau tente de le mapper sur la mémoire réelle afin qu'il puisse stocker une valeur réelle. Les processus réservent généralement beaucoup plus d’espace virtuel qu’ils n’y ont réellement accès, ce qui permet au noyau d’utiliser la RAM le plus efficacement possible. Cependant, la mémoire physique est toujours une ressource limitée et lorsque tout cela a été mappé à l'espace d'adressage virtuel, un certain espace d'adressage virtuel doit être éliminé pour libérer de la RAM.


5 D'abord un avertissement : si vous essayez ceci avec vm.overcommit_memory=0, assurez-vous d'enregistrer votre travail d'abord et fermez toutes les applications critiques, car le système sera gelé pendant ~ 90 secondes et certains processus vont mourir!

L'idée est d'exécuter une bombe fork qui expire après 90 secondes, les fourches allouant de l'espace et certaines écrivant de grandes quantités de données dans la RAM, tout en se rapportant à stderr.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>

/* 90 second "Verbose hungry fork bomb".
Verbose -> It jabbers.
Hungry -> It grabs address space, and it tries to eat memory.

BEWARE: ON A SYSTEM WITH 'vm.overcommit_memory=0', THIS WILL FREEZE EVERYTHING
FOR THE DURATION AND CAUSE THE OOM KILLER TO BE INVOKED.  CLOSE THINGS YOU CARE
ABOUT BEFORE RUNNING THIS. */

#define STEP 1 << 30 // 1 GB
#define DURATION 90

time_t now () {
    struct timeval t;
    if (gettimeofday(&t, NULL) == -1) {
        fprintf(stderr,"gettimeofday() fail: %s\n", strerror(errno));
        return 0;
    }
    return t.tv_sec;
}

int main (void) {
    int forks = 0;
    int i;
    unsigned char *p;
    pid_t pid, self;
    time_t check;
    const time_t start = now();
    if (!start) return 1;

    while (1) {
    // Get our pid and check the elapsed time.
        self = getpid();
        check = now();
        if (!check || check - start > DURATION) return 0;
        fprintf(stderr,"%d says %d forks\n", self, forks++);
    // Fork; the child should get its correct pid.
        pid = fork();
        if (!pid) self = getpid();
    // Allocate a big chunk of space.
        p = malloc(STEP);
        if (!p) {
            fprintf(stderr, "%d Allocation failed!\n", self);
            return 0;
        }
        fprintf(stderr,"%d Allocation succeeded.\n", self);
    // The child will attempt to use the allocated space.  Using only
    // the child allows the fork bomb to proceed properly.
        if (!pid) {
            for (i = 0; i < STEP; i++) p[i] = i % 256;
            fprintf(stderr,"%d WROTE 1 GB\n", self);
        }
    }
}                        

Compilez ceci gcc forkbomb.c -o forkbomb. Tout d'abord, essayez avec sysctl vm.overcommit_memory=2- vous obtiendrez probablement quelque chose comme:

6520 says 0 forks
6520 Allocation succeeded.
6520 says 1 forks
6520 Allocation succeeded.
6520 says 2 forks
6521 Allocation succeeded.
6520 Allocation succeeded.
6520 says 3 forks
6520 Allocation failed!
6522 Allocation succeeded.

Dans cet environnement, ce type de bombe à fourche ne va pas très loin. Notez que le nombre dans "dit N fourches" n'est pas le nombre total de processus, c'est le nombre de processus dans la chaîne / branche menant à celui-ci.

Maintenant, essayez avec vm.overcommit_memory=0. Si vous redirigez stderr vers un fichier, vous pouvez effectuer une analyse grossière par la suite, par exemple:

> cat tmp.txt | grep failed
4641 Allocation failed!
4646 Allocation failed!
4642 Allocation failed!
4647 Allocation failed!
4649 Allocation failed!
4644 Allocation failed!
4643 Allocation failed!
4648 Allocation failed!
4669 Allocation failed!
4696 Allocation failed!
4695 Allocation failed!
4716 Allocation failed!
4721 Allocation failed!

Seuls 15 processus n'ont pas pu allouer 1 Go, ce qui montre que l'heuristique pour overcommit_memory = 0 est affectée par l'état. Combien de processus y avait-il? En regardant la fin de tmp.txt, probablement> 100 000. Maintenant, comment peut-on réellement utiliser le 1 Go?

> cat tmp.txt | grep WROTE
4646 WROTE 1 GB
4648 WROTE 1 GB
4671 WROTE 1 GB
4687 WROTE 1 GB
4694 WROTE 1 GB
4696 WROTE 1 GB
4716 WROTE 1 GB
4721 WROTE 1 GB

Huit - ce qui a encore un sens, car à l'époque j'avais environ 3 Go de RAM libre et 6 Go de swap.

Jetez un oeil à vos journaux système après avoir fait cela. Vous devriez voir les scores des rapports du tueur OOM (entre autres); on peut supposer que cela concerne oom_badness.

boucle d'or
la source
l'échange n'est pas une solution (ou même liée) à la mémoire plutôt qu'à l'engagement. L'allocation de mémoire (par exemple: malloc) consiste à demander à la mémoire virtuelle d'être réservée, pas physique.
jlliagre
1
@jillagre: "échanger n'est pas une solution (ou même liée) à la mémoire plutôt qu'à l'engagement" -> Oui, en fait. Les pages rarement utilisées sont permutées hors de la RAM, ce qui laisse plus de RAM disponible pour traiter les défauts de page causés par la pagination / allocation de la demande (qui est le mécanisme qui rend possible un engagement plus). Les pages échangées peuvent également devoir être paginées à nouveau dans la RAM à un moment donné.
goldilocks
"L'allocation de mémoire (par exemple: malloc) consiste à demander à la mémoire virtuelle d'être réservée, pas physique." -> D'accord, mais le noyau pourrait (et éventuellement, dira) non lorsqu'il n'y aura plus de mappages physiques . Ce ne serait certainement pas parce qu'un processus est à court d'espace d'adressage virtuel (ou du moins pas habituellement, car c'est également possible, au moins sur les systèmes 32 bits).
goldilocks
La pagination de la demande n'est pas ce qui rend possible la mémoire sur l'engagement. Linux a certainement surchargé la mémoire sur des systèmes sans aucune zone de swap. Vous pourriez confondre la mémoire avec l'engagement et la pagination de la demande. Si Linux dit «non» à malloc avec un processus 64 bits, c'est-à-dire s'il n'est pas configuré pour toujours surcharger, ce serait soit à cause de la corruption de mémoire, soit à cause de la somme de toutes les réservations de mémoire (qu'elles soient mappées ou non sur la RAM ou le disque) dépasse un seuil seuil en fonction de la configuration. Cela n'a rien à voir avec l'utilisation de la RAM car cela peut se produire même s'il y a encore de la RAM libre.
jlliagre
"La pagination de la demande n'est pas ce qui rend possible la mémoire sur l'engagement." -> Peut-être vaudrait-il mieux dire que c'est l'adressage virtuel qui permet à la fois la pagination de la demande et le sur-engagement. "Linux a certainement trop validé la mémoire sur des systèmes sans aucune zone de swap." -> Évidemment, puisque la pagination de la demande ne nécessite pas de swap; la pagination de la demande de swap n'est qu'un exemple spécial de la pagination de la demande. Une fois de plus, l'échange est une solution au sur-engagement, non pas dans le sens où il résout le problème, mais dans le sens qui aidera à prévenir les événements de MOO potentiels qui pourraient résulter d'un sur-engagement.
goldilocks
16

Cela ne vous arrivera pas si vous ne chargez que 1 Go de données en mémoire. Et si vous chargez beaucoup plus? Par exemple, je travaille souvent avec des fichiers énormes contenant des millions de probabilités qui doivent être chargés dans R. Cela prend environ 16 Go de RAM.

L'exécution du processus ci-dessus sur mon ordinateur portable entraînera un échange comme un fou dès que mes 8 Go de RAM auront été remplis. Cela, à son tour, ralentira tout car la lecture à partir du disque est beaucoup plus lente que la lecture à partir de la RAM. Et si j'ai un ordinateur portable avec 2 Go de RAM et seulement 10 Go d'espace libre? Une fois que le processus a pris toute la RAM, il remplira également le disque car il écrit pour permuter et il ne me reste plus de RAM et plus d'espace pour swap (les gens ont tendance à limiter le swap à une partition dédiée plutôt qu'à un swapfile pour exactement cette raison). C'est là que le tueur OOM entre en jeu et commence à tuer les processus.

Ainsi, le système peut en effet manquer de mémoire. De plus, les systèmes à très forte permutation peuvent devenir inutilisables bien avant que cela ne se produise simplement en raison des opérations d'E / S lentes dues à la permutation. On veut généralement éviter autant que possible l'échange. Même sur les serveurs haut de gamme dotés de SSD rapides, les performances diminuent clairement. Sur mon ordinateur portable, qui a un lecteur classique de 7200 tr / min, tout échange important rend essentiellement le système inutilisable. Plus il échange, plus il ralentit. Si je ne tue pas le processus offensant rapidement, tout se bloque jusqu'à ce que le tueur OOM intervienne.

terdon
la source
5

Les processus ne sont pas tués quand il n'y a plus de RAM, ils sont tués quand ils ont été trichés de cette façon:

  • Le noyau Linux permet généralement aux processus d'allouer (c'est-à-dire de réserver) une quantité de mémoire virtuelle qui est plus grande que ce qui est réellement disponible (une partie de la RAM + toute la zone de swap)
  • tant que les processus n'accèdent qu'à un sous-ensemble des pages qu'ils ont réservées, tout se passe bien.
  • si après un certain temps, un processus essaie d'accéder à une page dont il est propriétaire mais qu'aucune autre page n'est libre, une situation de mémoire insuffisante se produit
  • Le tueur OOM sélectionne l'un des processus, pas nécessairement celui qui a demandé une nouvelle page, et il suffit de le tuer pour récupérer la mémoire virtuelle.

Cela peut se produire même lorsque le système n'échange pas activement, par exemple si la zone d'échange est remplie de pages de mémoire de démons endormis.

Cela ne se produit jamais sur les systèmes d'exploitation qui ne surchargent pas la mémoire. Avec eux, aucun processus aléatoire n'est tué, mais le premier processus demandant de la mémoire virtuelle alors qu'il est épuisé renvoie malloc (ou similaire) par erreur. On lui donne ainsi une chance de bien gérer la situation. Cependant, sur ces systèmes d'exploitation, il peut également arriver que le système manque de mémoire virtuelle alors qu'il reste de la RAM libre, ce qui est assez déroutant et généralement mal compris.

jlliagre
la source
3

Lorsque la RAM disponible est épuisée, le noyau commence à échanger des bits de traitement sur le disque. En fait, le noyau commence à échanger un lorsque la RAM est presque épuisée: il commence à échanger de manière proactive lorsqu'il a un moment d'inactivité, afin d'être plus réactif si une application nécessite soudainement plus de mémoire.

Notez que la RAM n'est pas utilisée uniquement pour stocker la mémoire des processus. Sur un système sain typique, seulement environ la moitié de la RAM est utilisée par les processus, et l'autre moitié est utilisée pour le cache disque et les tampons. Cela fournit un bon équilibre entre les processus en cours d'exécution et les entrées / sorties de fichiers.

L'espace de swap n'est pas infini. À un certain point, si les processus continuent d'allouer de plus en plus de mémoire, les données de débordement de la RAM rempliront le swap. Lorsque cela se produit, les processus qui tentent de demander plus de mémoire voient leur demande refusée.

Par défaut, Linux surcharge la mémoire. Cela signifie qu'il permet parfois à un processus de s'exécuter avec la mémoire qu'il a réservée, mais non utilisée. La raison principale du sur-engagement est la façon dont fonctionne la fourche . Lorsqu'un processus lance un sous-processus, le processus enfant fonctionne conceptuellement dans une réplique de la mémoire du parent - les deux processus ont initialement de la mémoire avec le même contenu, mais ce contenu divergera à mesure que les processus effectueront des modifications chacun dans leur propre espace. Pour l'implémenter complètement, le noyau devrait copier toute la mémoire du parent. Cela rendrait le forking lent, donc le noyau pratique la copie sur écriture: au départ, l'enfant partage toute sa mémoire avec le parent; chaque fois que l'un des processus écrit sur une page partagée, le noyau crée une copie de cette page pour rompre le partage.

Souvent, un enfant laisse de nombreuses pages intactes. Si le noyau allouait suffisamment de mémoire pour répliquer l'espace mémoire du parent sur chaque fork, beaucoup de mémoire serait gaspillée dans les réservations que les processus enfants n'allaient jamais utiliser. D'où un engagement excessif: le noyau ne réserve qu'une partie de cette mémoire, sur la base d'une estimation du nombre de pages dont l'enfant aura besoin.

Si un processus essaie d'allouer de la mémoire et qu'il n'y a pas assez de mémoire, le processus reçoit une réponse d'erreur et la traite comme bon lui semble. Si un processus demande indirectement de la mémoire en écrivant sur une page partagée qui doit être non partagée, c'est une autre histoire. Il n'y a aucun moyen de signaler cette situation à l'application: elle pense y avoir des données inscriptibles et pourrait même les lire - c'est juste que l'écriture implique une opération légèrement plus élaborée sous le capot. Si le noyau n'est pas en mesure de fournir une nouvelle page de mémoire, tout ce qu'il peut faire est de tuer le processus demandeur ou de tuer un autre processus pour remplir la mémoire.

Vous pourriez penser à ce stade que la suppression du processus de demande est la solution évidente. Mais en pratique, ce n'est pas si bon. Le processus peut être un processus important qui n'a besoin que d'accéder à l'une de ses pages maintenant, alors qu'il peut y avoir d'autres processus moins importants en cours d'exécution. Ainsi, le noyau comprend des heuristiques complexes pour choisir les processus à tuer - le (in) célèbre tueur OOM .

Gilles 'SO- arrête d'être méchant'
la source
2

Juste pour ajouter un autre point de vue à partir des autres réponses, de nombreux VPS hébergent plusieurs machines virtuelles sur un serveur donné. Toute machine virtuelle unique aura une quantité spécifiée de RAM pour son propre usage. De nombreux fournisseurs proposent une "RAM éclatée", dans laquelle ils peuvent utiliser la RAM au-delà de la quantité qu'ils ont désignée. Ceci est destiné à être utilisé uniquement à court terme, et ceux qui vont au-delà de cette quantité de temps prolongée peuvent être pénalisés par les processus de destruction de l'hôte pour réduire la quantité de RAM utilisée afin que les autres ne souffrent pas de la machine hôte étant surchargée.

agweber
la source
-1

Quelque temps Linux prend de l'espace virtuel externe. C'est la partition de swap. Lorsque Ram est rempli, Linux prend cette zone de swap pour exécuter un processus de faible priorité.

Bizzon
la source
1
Aucun processus n'est exécuté à partir du swap. La mémoire virtuelle est divisée en unités distinctes de taille égale appelées pages. Lorsque la mémoire physique est libérée, les pages de faible priorité sont supprimées de la RAM. Bien que les pages du cache de fichiers soient sauvegardées par le système de fichiers, les pages anonymes doivent être stockées dans swap. La priorité d'une page n'est pas directement liée à la priorité du processus auquel elle appartient, mais à sa fréquence d'utilisation. Si un processus en cours essaie d'accéder à une page qui n'est pas dans la mémoire physique, une erreur de page est générée et le processus est préempté en faveur d'un autre processus pendant que les pages nécessaires sont extraites du disque.
Thomas Nyman