251 votes

Pourquoi malloc + memset est plus lent que calloc?

Il est connu que la calloc est différent de celui d' malloc en ce qu'il initialise la mémoire allouée. Avec calloc, la mémoire est mise à zéro. Avec malloc, la mémoire n'est pas effacée.

Donc, dans le travail quotidien, je considère calloc comme malloc+memset. D'ailleurs, pour le fun, j'ai écrit le code suivant pour une référence.

Le résultat est déroutant.

Code 1:

#include<stdio.h>
#include<stdlib.h>
#define BLOCK_SIZE 1024*1024*256
int main()
{
        int i=0;
        char *buf[10];
        while(i<10)
        {
                buf[i] = (char*)calloc(1,BLOCK_SIZE);
                i++;
        }
}

Sortie de Code 1:

time ./a.out  
**real 0m0.287s**  
user 0m0.095s  
sys 0m0.192s  

Code 2:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BLOCK_SIZE 1024*1024*256
int main()
{
        int i=0;
        char *buf[10];
        while(i<10)
        {
                buf[i] = (char*)malloc(BLOCK_SIZE);
                memset(buf[i],'\0',BLOCK_SIZE);
                i++;
        }
}

Sortie de Code 2:

time ./a.out   
**real 0m2.693s**  
user 0m0.973s  
sys 0m1.721s  

Remplacement d' memset avec bzero(buf[i],BLOCK_SIZE) Code 2 donne le même résultat.

Ma question est: Pourquoi est - malloc+memset , donc beaucoup plus lent que l' calloc? Comment peut - calloc ?

448voto

Dietrich Epp Points 72865

C'est probablement en raison de votre grande taille d'allocation. Vous pourriez lire sur le fonctionnement de la mémoire virtuelle et les OS de la théorie.

Lorsque vous allouez une assez grande région de la mémoire (le seuil est souvent 1 MiB, si ma mémoire est bonne), la plupart des allocateurs obtiendrez une nouvelle région de la mémoire du noyau à l'aide de "mmap" juste pour cette région. Cependant, lorsque "mmap" vous donne de nouvelles pages de mémoire, ils ont à être initialisé à zéro (lors de l'utilisation d' MAP_ANONYMOUS). S'ils ne l'étaient pas, ils seraient rempli de toutes sortes de fichiers depuis d'autres applications - et c'est une grave faille de sécurité. Que faire si la racine a été l'édition d' /etc/shadow avec ces pages? La même chose s'applique également si "malloc" manque de mémoire pour les petits les allocations et les appels "sbrk" pour obtenir plus.

Mais ce serait trop long à zéro tous que la mémoire. Le noyau tricheurs. Il y a une page de mémoire déjà mise à zéro mise de côté. Toutes les pages de la nouvelle allocation point à cette partie de la ram physique, qui est partagé entre tous les processus sur le système, donc il ne fait pas utiliser toute la mémoire. Il est marqué comme étant en lecture seule. Dès que vous écrivez, le processeur génère une exception. Le noyau du gestionnaire d'exception puis s'empare d'une page de mémoire vive (éventuellement permutation de quelque chose d'autre), la remplit avec des zéros et des cartes dans votre espace d'adressage du processus. Le "calloc" fonction peut exploiter cette.

(En fait, le noyau peut aller plus loin, et ont "mmap" ne rien à votre espace mémoire du processus jusqu'à ce que vous lisez à partir d'elle.)

Le "memset" la mise en œuvre des touches chaque page dans l'attribution, ce qui beaucoup plus l'utilisation de la mémoire - il oblige le noyau d'allouer ces pages maintenant, au lieu d'attendre jusqu'à ce que vous utilisez réellement.

Le "calloc" de mise en œuvre de change juste une page de quelques tables, consomme très peu de mémoire, écrit à très peu de mémoire, et les retours. Sur la plupart des systèmes, vous pouvez même attribuer plus de mémoire que votre système peut prendre en charge (plus de RAM + swap) sans aucun problème, tant que vous n'écrivez pas à tout cela. (Cette fonctionnalité est un peu controversée sur les systèmes d'exploitation qui permettent à ce sujet).

Certains systèmes ne prennent pas en charge la mémoire virtuelle: très anciens (pensez 80286) et certains systèmes embarqués. Sur ces systèmes, la vitesse pourrait être beaucoup plus proche.


Il y a quelques suppositions dans d'autres réponses que émettons l'hypothèse que "memset" est plus lent que "calloc" parce que "memset" ne peut pas supposer que la mémoire est aligné. Voici comment un "memset" travaux de mise en œuvre:

function memset(dest, c, len)
    // one byte at a time, until the dest is aligned...
    while (len > 0 && ((unsigned int)dest & 15))
        *dest++ = c
        len -= 1
    // now write big chunks at a time (processor-specific)...
    // block size might not be 16, it's just pseudocode
    while (len >= 16)
        // some optimized vector code goes here
        // glibc uses SSE2 when available
        dest += 16
        len -= 16
    // the end is not aligned, so one byte at a time
    while (len > 0)
        *dest++ = c
        len -= 1

Dans un 256 MiB morceau, qui est le premier et le dernier tour de boucle vont être négligeable, et au moyen de la boucle est la même que l'hypothétique calloc boucle. Certains compilateurs inline "memset", et peut même en déduire que la suite de "malloc" est l'alignement de bloc. Et un typique "calloc" la mise en œuvre appelle simplement "memset" de toute façon - "calloc" est généralement écrit en C, et il est souvent portable sur différents systèmes d'exploitation.

L'autre suppose que j'ai vu, c'est que "malloc" déjà initialise la mémoire, donc "memset" initialise deux fois. C'est techniquement vrai dans ce cas. Cependant, il ne compte que pour environ un facteur deux de la vitesse. Le "calloc" version est de dix à quinze cents fois plus vite. Les chiffres ne prennent pas en charge la conclusion.


Note de bas de page: Juste pour rire, j'ai programmé les deux programmes sur deux de mes ordinateurs. Sur mes OS X / PowerPC boîte, le memset version était plus 1500x plus lent (8 s contre 5 ms). Sur mon Linux / x86 boîte, le memset version couru pour 35x aussi longtemps avant de segfaulting (attendus, que l'ordinateur dispose de moins de mémoire vive - note, cependant, que la calloc version n'a pas de crash).

12voto

Chris Lutz Points 34157

Parce que sur de nombreux systèmes, pendant le temps de traitement libre, le système d'exploitation va libérer la mémoire libre à zéro et la marquer comme sûre pour calloc() , donc quand vous appelez calloc() , il peut déjà avoir de la mémoire libre et mise à zéro pour vous donner.

1voto

Stewart Points 3104

Sur certaines plates-formes dans certains modes, malloc initialise la mémoire à une valeur généralement différente de zéro avant de la renvoyer, de sorte que la seconde version pourrait bien initialiser la mémoire deux fois.

-3voto

TheCodeArtist Points 6837

Optimisation de derrière les coulisses??

L' memset() appel serait de ralentir vos numéros.

Essayez de profilage un code3 avec seulement la suite, pour se faire une idée:

    while(i<10)
    {
            buf[i] = (char*)malloc(BLOCK_SIZE);
            i++;
    }

Alors qu' memset() peut être utilisée pour définir la mémoire à zéro. c'est juste un "cas spécial" de l'utilisation de memset() pour qui il n'est pas optimisée.

calloc() est juste conçu pour le faire (Alloc mem init-ed 0x00 des valeurs). Cela lui permet de faire toutes sortes de derrière les coulisses de la tricherie et pas vraiment d'allocation de pages et le "zéro" immédiatement.


Donc, qu'est - memset() le faire à l'intérieur?

Voici un extrait de MS C run-time codes:

void * __cdecl memset (void *dst, int val, size_t count)
{

    void *start = dst;

    extern void RtlFillMemory( void *, size_t count, char );  

    RtlFillMemory( dst, count, (char)val );

    while (count--)  {
        *(char *)dst = (char)val;
        dst = (char *)dst + 1;
    }

    return(start);

}
  • En conclusion, memset initialise un bloc de mémoire et remplit effectivement avec "zéro"es.

Mise à jour: Indépendamment de la mise en œuvre des optimisations, le besoin de "toucher" chaque octet de chaque page afin de "zéro", serait toujours le faire memset() plus lent que l' calloc(). +1 pour de Dietrich réponse ci-dessus pour une explication détaillée.

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