72 votes

Malloc crée-t-il paresseusement les pages de support pour une allocation sous Linux (et d'autres plates-formes)?

Sous Linux, si je devais malloc(1024 * 1024 * 1024), ce qui ne malloc?

Je suis sûr qu'il attribue une adresse virtuelle à l'attribution (en parcourant la liste d'espace libre et la création d'une nouvelle cartographie si nécessaire), mais faut-il réellement créer 1 GiB vaut la peine de changer l'ordre des pages? Ou faut-il mprotect la plage d'adresses et de créer les pages lorsque vous avez réellement toucher comme mmap ?

(Je suis en précisant Linux parce que la norme est silencieuse sur ces sortes de détails, mais je serais intéressé de savoir ce que les autres plateformes de faire aussi bien.)

41voto

Remus Rusanu Points 159382

Linux n'différé de répartition de page, aka. optimiste de l'allocation de mémoire'. Le mémoire que vous obtenez de retour de malloc n'est pas étayée par rien, et quand vous la touchez, vous pourriez obtenir un OOM condition (si il n'y a pas d'espace de swap pour la page que vous demandez), auquel cas un processus est résilié sans ménagement.

Voir, par exemple, http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html

16voto

Aiden Bell Points 19856

Cette http://www.win.tue.nl/~aeb/linux/lk/lk-9.html Est un bon document

Il contient les programmes suivants qui démontrent Linux de la gestion de la mémoire physique et réelle de la mémoire et de explique le Noyau lui-même.

En général, le premier programme de démonstration permettra d'obtenir une très grande quantité de mémoire avant de malloc() renvoie la valeur NULL. Le deuxième programme de démonstration permettra d'obtenir une plus petite quantité de mémoire, maintenant que précédemment obtenu mémoire est effectivement utilisé. Le troisième programme sera le même montant que le premier programme, puis est tué quand il veut utiliser sa mémoire.

Programme de démonstration 1: allouer de la mémoire sans l'utiliser.

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

int main (void) {
        int n = 0;

        while (1) {
                if (malloc(1<<20) == NULL) {
                        printf("malloc failure after %d MiB\n", n);
                        return 0;
                }
                printf ("got %d MiB\n", ++n);
        }
}

Programme de démonstration 2: allouer de la mémoire et le fait de le toucher.

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

int main (void) {
        int n = 0;
        char *p;

        while (1) {
                if ((p = malloc(1<<20)) == NULL) {
                        printf("malloc failure after %d MiB\n", n);
                        return 0;
                }
                memset (p, 0, (1<<20));
                printf ("got %d MiB\n", ++n);
        }
}

Programme de démonstration 3: alloue d'abord, et de les utiliser plus tard.

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

#define N       10000

int main (void) {
        int i, n = 0;
        char *pp[N];

        for (n = 0; n < N; n++) {
                pp[n] = malloc(1<<20);
                if (pp[n] == NULL)
                        break;
        }
        printf("malloc failure after %d MiB\n", n);

        for (i = 0; i < n; i++) {
                memset (pp[i], 0, (1<<20));
                printf("%d\n", i+1);
        }

        return 0;
}

(Sur un système qui fonctionne bien, comme Solaris, les trois programmes de démonstration obtenir la même quantité de mémoire et ne se bloque pas mais voir malloc() renvoie NULL.)

10voto

Robert S. Barnes Points 17244

J'ai donné cette réponse à un autre post sur le même sujet:

Certains d'allocateurs de paresseux?

Cela commence un peu hors sujet ( et puis je vais l'attacher à votre question ), mais ce qui se passe est similaire à ce qui se passe quand vous la fourche d'un processus dans Linux. Lorsque la fourche il y a un mécanisme appelé la copie sur écriture qui ne copie que la mémoire de l'espace pour le nouveau processus lorsque la mémoire est écrit trop. De cette façon, si la fourche processus exec est un nouveau programme tout de suite, alors vous avez sauvé la surcharge de la copie de l'original des programmes de la mémoire.

Pour en revenir à votre question, l'idée est similaire. Comme d'autres l'ont souligné, demandant à la mémoire vous fait de l'espace de mémoire virtuelle immédiatement, mais les pages ne sont attribués lors de leur écrire.

Quel est le but de tout cela? Il rend fondamentalement mallocing de la mémoire plus ou moins constante de temps de l'opération Big O(1) au lieu d'un Grand O(n) opération ( similaire à la façon dont le Linux planificateur de spreads, c'est le travail au lieu de le faire dans un gros morceau ).

Pour démontrer ce que je veux dire j'ai fait l'expérience suivante:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc 

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef 

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites 

real    0m0.006s
user    0m0.000s
sys 0m0.008s

Le bigmalloc programme alloue 20 millions d'entiers, mais ne pas faire n'importe quoi avec eux. deadbeef écrit un int à chaque page, résultant dans 19531 écrit et justwrites alloue 19531 ints et de zéros. Comme vous pouvez le voir deadbeef prend 100 fois plus de temps pour exécuter que bigmalloc et environ 50 fois plus longtemps que justwrites.

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

return 0;
}

.

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

// immediately write to each page to simulate all at once allocation

// assuming 4k page size on 32bit machine

for ( int* end = big + 20000000; big < end; big+=1024 ) *big = 0xDEADBEEF; 

return 0;

}

.

#include <stdlib.h>

int main(int argc, char **argv) {

int *big = calloc(sizeof(int),19531); // number of writes

return 0;
}

5voto

Paul Betts Points 41354

Sous Windows, les pages sont validées (c’est-à-dire que la mémoire libre disponible diminue), mais ne sont en réalité allouées que lorsque vous touchez les pages (en lecture ou en écriture).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X