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).