@ddddavidee Moi aussi, j'ai trouvé ce blog après que j'étais insatisfait de tant de réponses sur le net. Nathaniel J. Smith mérite plus de 100 points SO pour son analyse.
calloc()vous donne un tampon zéro initialisé, tout en malloc()laissant la mémoire non initialisée.
Pour les allocations importantes, la plupart des callocimplémentations sous les OS traditionnels obtiendront des pages à zéro connu de l'OS (par exemple via POSIX mmap(MAP_ANONYMOUS)ou Windows VirtualAlloc), il n'a donc pas besoin de les écrire dans l'espace utilisateur. C'est ainsi que la normale mallocobtient plus de pages du système d'exploitation; callocprofite simplement de la garantie de l'OS.
Cela signifie que la callocmémoire peut toujours être «propre» et allouée paresseusement, et la copie sur écriture mappée sur une page physique partagée de zéros à l'échelle du système. (En supposant un système avec mémoire virtuelle.)
Certains compilateurs peuvent même optimiser malloc + memset (0) en calloc pour vous, mais vous devez utiliser explicitement calloc si vous voulez que la mémoire soit lue 0.
Si vous ne lirez jamais la mémoire avant de l'écrire, utilisez-la mallocafin qu'elle puisse (potentiellement) vous donner de la mémoire sale à partir de sa liste libre interne au lieu d'obtenir de nouvelles pages du système d'exploitation. (Ou au lieu de mettre à zéro un bloc de mémoire sur la liste gratuite pour une petite allocation).
Les implémentations intégrées de callocpeuvent laisser à calloclui-même la mémoire zéro s'il n'y a pas de système d'exploitation, ou ce n'est pas un système d'exploitation multi-utilisateurs sophistiqué qui met à zéro les pages pour arrêter les fuites d'informations entre les processus.
Sur Linux embarqué, malloc pourrait mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS), qui n'est activé que pour certains noyaux intégrés car il n'est pas sécurisé sur un système multi-utilisateur.
Les variantes * alloc sont assez mnémoniques - clear-alloc, memory-alloc, re-alloc.
Cascabel
43
Utilisez malloc () si vous allez définir tout ce que vous utilisez dans l'espace alloué. Utilisez calloc () si vous voulez laisser des parties des données non initialisées - et il serait avantageux de mettre à zéro les parties non définies.
Jonathan Leffler
268
callocn'est pas nécessairement plus cher, car OS peut faire quelques trucs pour l'accélérer. Je sais que FreeBSD, quand il obtient un temps processeur inactif, l'utilise pour exécuter un processus simple qui fait le tour et met à zéro les blocs de mémoire désalloués, et marque les blocs ainsi traités avec un indicateur. Ainsi, lorsque vous le faites calloc, il essaie d'abord de trouver l'un de ces blocs pré-mis à zéro et de vous le donner - et il en trouvera probablement un.
Pavel Minaev
28
J'ai tendance à penser que si votre code devient "plus sûr" à la suite d'allocations à zéro par défaut, alors votre code n'est pas suffisamment sûr, que vous utilisiez malloc ou calloc. L'utilisation de malloc est un bon indicateur que les données doivent être initialisées - je n'utilise calloc que dans les cas où ces 0 octets sont réellement significatifs. Notez également que calloc ne fait pas nécessairement ce que vous pensez pour les types non-char. Personne n'utilise plus vraiment les représentations de piège, ou les flottants non-IEEE, mais ce n'est pas une excuse pour penser que votre code est vraiment portable quand il ne l'est pas.
Steve Jessop
18
@SteveJessop "Safer" n'est pas le bon mot. Je pense que "déterministe" est le meilleur terme. Un code plus déterministe que d'avoir des échecs qui dépendent du timing et des séquences de données, sera plus facile à isoler les échecs. Calloc est parfois un moyen facile d'obtenir ce déterminisme, par opposition à l'initialisation explicite.
dennis
362
Une différence moins connue est que dans les systèmes d'exploitation avec une allocation de mémoire optimiste, comme Linux, le pointeur renvoyé par mallocn'est pas soutenu par de la mémoire réelle jusqu'à ce que le programme le touche réellement.
calloctouche en effet la mémoire (il y écrit des zéros) et donc vous serez sûr que le système d'exploitation sauvegarde l'allocation avec de la RAM réelle (ou swap). C'est aussi pourquoi il est plus lent que malloc (non seulement il doit le mettre à zéro, le système d'exploitation doit également trouver une zone de mémoire appropriée en échangeant éventuellement d'autres processus)
Voir par exemple cette question SO pour plus de détails sur le comportement de malloc
callocpas besoin d'écrire des zéros. Si le bloc alloué se compose principalement de nouvelles pages nulles fournies par le système d'exploitation, il peut les laisser intactes. Bien sûr, cela nécessite callocd'être réglé sur le système d'exploitation plutôt que sur une fonction de bibliothèque générique malloc. Ou, un implémenteur pourrait faire calloccomparer chaque mot à zéro avant de le mettre à zéro. Cela ne ferait pas gagner de temps, mais cela éviterait de salir les nouvelles pages.
R .. GitHub ARRÊTEZ D'AIDER LA GLACE
3
@R .. note intéressante. Mais en pratique, de telles implémentations existent-elles à l'état sauvage?
Isak Savo
10
Toutes les dlmallocimplémentations similaires ignorent memsetsi le bloc a été obtenu via de mmapnouvelles pages anonymes (ou équivalent). Habituellement, ce type d'allocation est utilisé pour les gros morceaux, à partir de 256 Ko environ. Je ne connais aucune implémentation qui fasse la comparaison avec zéro avant d'écrire zéro à part la mienne.
R .. GitHub ARRÊTEZ D'AIDER LA GLACE
1
omallocsaute également le memset; callocn'a jamais besoin de toucher à des pages qui ne sont pas déjà utilisées par l'application (cache de pages). Cependant, les callocimplémentations extrêmement primitives diffèrent.
mirabilos
10
Le calloc de glibc vérifie s'il obtient de la mémoire fraîche du système d'exploitation. Si tel est le cas, il sait qu'il n'a PAS besoin de l'écrire, car mmap (..., MAP_ANONYMOUS) renvoie une mémoire déjà mise à zéro.
Peter Cordes
112
Un avantage souvent négligé callocest que (implémentations conformes de) il vous aidera à vous protéger contre les vulnérabilités de débordement d'entier. Comparer:
Le premier pourrait entraîner une petite allocation et des dépassements de tampon ultérieurs, s'il countest supérieur à SIZE_MAX/sizeof *bar. Ce dernier échouera automatiquement dans ce cas car un objet de cette taille ne peut pas être créé.
Bien sûr, vous devrez peut-être être à la recherche d'implémentations non conformes qui ignorent simplement la possibilité de débordement.
Apparemment, le débordement arithmétique a été à l'origine du trou d'OpenSSH en 2002. Bon article d'OpenBSD sur les dangers de cela avec des fonctions liées à la mémoire: undeadly.org/cgi?action=article&sid=20060330071917
Philip P.
4
@KomradeP .: Intéressant. Malheureusement, l'article que vous avez lié contient des informations erronées dès le début. L'exemple avec charn'est pas un débordement mais plutôt une conversion définie par l'implémentation lors de la réaffectation du résultat dans un charobjet.
R .. GitHub STOP HELPING ICE
Il est probablement là uniquement à des fins d'illustration. Parce que le compilateur est susceptible d'optimiser cela de toute façon. Le mien se compile dans cet asm: pousser 1.
Philip P.
1
@tristopia: Le fait n'est pas que le code est exploitable sur toutes les implémentations, mais qu'il est incorrect sans hypothèses supplémentaires et donc pas une utilisation correcte / portable.
R .. GitHub STOP HELPING ICE
3
@tristopia: Si votre mode de pensée est " size_t64 bits donc ce n'est pas un problème", c'est une façon de penser erronée qui va conduire à des bugs de sécurité. size_test un type abstrait qui représente des tailles, et il n'y a aucune raison de penser que le produit arbitraire d'un nombre 32 bits et d'un size_t(remarque: sizeof *barpourrait en principe être supérieur à 2 ^ 32 sur une implémentation C 64 bits!) s'intègre size_t.
R .. GitHub STOP HELPING ICE
37
La documentation fait ressembler le calloc à malloc, qui initialise simplement la mémoire à zéro; ce n'est pas la principale différence! L'idée de calloc est d'abstraire la sémantique de copie sur écriture pour l'allocation de mémoire. Lorsque vous allouez de la mémoire avec calloc, tout est mappé sur la même page physique qui est initialisée à zéro. Lorsqu'une des pages de la mémoire allouée est écrite dans une page physique est allouée. Ceci est souvent utilisé pour créer des tables de hachage ÉNORMES, par exemple car les parties de hachage vides ne sont pas soutenues par une mémoire supplémentaire (pages); ils pointent joyeusement vers la page unique initialisée à zéro, qui peut même être partagée entre les processus.
Toute écriture sur une adresse virtuelle est mappée sur une page, si cette page est la page zéro, une autre page physique est allouée, la page zéro y est copiée et le flux de contrôle est renvoyé au processus client. Cela fonctionne de la même manière que les fichiers mappés en mémoire, la mémoire virtuelle, etc. fonctionnent .. il utilise la pagination.
Il n'y a aucune différence dans la taille du bloc de mémoire alloué. callocremplit simplement le bloc de mémoire avec un motif physique de zéro. Dans la pratique, on suppose souvent que les objets situés dans le bloc de mémoire alloué avec callocont une valeur initiale comme s'ils avaient été initialisés avec un littéral 0, c'est-à-dire que les entiers devraient avoir la valeur de 0, les variables à virgule flottante - la valeur de0.0 , les pointeurs - la pointeur nul appropriée , etc.
Du point de vue pédant cependant, calloc(ainsi que memset(..., 0, ...)) n'est garanti que pour initialiser correctement (avec des zéros) les objets de type unsigned char. Tout le reste n'est pas garanti d'être correctement initialisé et peut contenir ce qu'on appelle une représentation d'interruption , ce qui provoque un comportement non défini. En d'autres termes, pour tout type autre que unsigned charle motif tout-à-zéro susmentionné, il pourrait représenter une valeur illégale, une représentation d'interruption.
Plus tard, dans l'un des rectificatifs techniques à la norme C99, le comportement a été défini pour tous les types d'entiers (ce qui est logique). Autrement dit, dans le langage C actuel, vous ne pouvez initialiser que les types entiers avec calloc(et memset(..., 0, ...)). L'utiliser pour initialiser autre chose dans le cas général conduit à un comportement indéfini, du point de vue du langage C.
En pratique, callocça marche, comme nous le savons tous :), mais c'est à vous de décider si vous souhaitez l'utiliser (compte tenu de ce qui précède). Personnellement, je préfère l'éviter complètement, utiliser à la mallocplace et effectuer ma propre initialisation.
Enfin, un autre détail important est celui qui callocest nécessaire pour calculer la taille finale du bloc en interne , en multipliant la taille des éléments par le nombre d'éléments. Ce faisant, vous callocdevez surveiller les éventuels débordements arithmétiques. Il en résultera une allocation infructueuse (pointeur nul) si la taille de bloc demandée ne peut pas être calculée correctement. Pendant ce temps, votre mallocversion n'essaie pas de surveiller les débordements. Il allouera une certaine quantité de mémoire "imprévisible" en cas de débordement.
Par le paragraphe "autre détail important": cela semble poser memset(p, v, n * sizeof type);problème car il n * sizeof typepeut déborder. Je suppose que je devrai utiliser une for(i=0;i<n;i++) p[i]=v;boucle pour un code robuste.
chux
Il serait utile qu'il existe un moyen standard par lequel le code pourrait affirmer qu'une implémentation doit utiliser all-bits-zero comme pointeur nul (refusant la compilation sinon), car il existe des implémentations qui utilisent d'autres représentations de pointeur nul, mais elles sont relativement rare; le code qui n'a pas à s'exécuter sur de telles implémentations peut être plus rapide s'il peut utiliser calloc () ou memset pour initialiser des tableaux de pointeurs.
supercat
@chux Non, si un tableau avec des néléments existe là où un élément a la taille sizeof type, il n*sizeof typene peut pas déborder, car la taille maximale de tout objet doit être inférieure à SIZE_MAX.
12431234123412341234123
@ 12431234123412341234123 vrai sur un tableau taille <= SIZE_MAX, mais il n'y a pas de tableaux ici. Le pointeur renvoyé par calloc()peut pointer vers la mémoire allouée qui dépasse SIZE_MAX. De nombreuses implémentations limitent le produit des 2 arguments calloc()à SIZE_MAX, mais la spécification C n'impose pas cette limite.
Lors de l'allocation de mémoire à l'aide de calloc (), la quantité de mémoire demandée n'est pas allouée immédiatement. Au lieu de cela, toutes les pages qui appartiennent au bloc de mémoire sont connectées à une seule page contenant tous les zéros par une magie MMU (liens ci-dessous). Si de telles pages sont uniquement lues (ce qui était vrai pour les tableaux b, c et d dans la version originale du test de performances), les données sont fournies à partir de la page zéro unique, qui - bien sûr - tient dans le cache. Voilà pour les noyaux de boucles liés à la mémoire. Si une page est écrite (quelle que soit la manière), une erreur se produit, la page «réelle» est mappée et la page zéro est copiée en mémoire. C'est ce qu'on appelle la copie sur écriture, une approche d'optimisation bien connue (que j'ai même enseignée plusieurs fois dans mes conférences C ++). Après ça,
C'est mieux car il sizeof(Item)est connu du compilateur au moment de la compilation et le compilateur le remplacera dans la plupart des cas par les meilleures instructions possibles pour mettre à zéro la mémoire. D'un autre côté, si cela memsetse produit calloc, la taille du paramètre de l'allocation n'est pas compilée dans le calloccode et réel memsetest souvent appelé, qui contiendrait généralement du code pour effectuer le remplissage octet par octet jusqu'à la limite longue, puis cycle pour remplir la mémoire en sizeof(long)morceaux et enfin le remplissage octet par octet de l'espace restant. Même si l'allocateur est suffisamment intelligent pour en appeler, aligned_memsetce sera toujours une boucle générique.
Une exception notable serait lorsque vous faites malloc / calloc d'une très grande partie de la mémoire (quelques power_of_two kilobytes), auquel cas l'allocation peut être effectuée directement à partir du noyau. Comme les noyaux de système d'exploitation mettent généralement à zéro toute la mémoire qu'ils donnent pour des raisons de sécurité, un calloc suffisamment intelligent peut simplement le renvoyer sans mise à zéro supplémentaire. Encore une fois - si vous allouez simplement quelque chose que vous savez petit, vous pourriez être mieux avec malloc + memset en termes de performances.
+1 pour le rappel qu'une implémentation générique d'une fonctionnalité dans une bibliothèque système n'est pas nécessairement plus rapide que la même opération dans le code utilisateur.
Patrick Schlüter
1
Il y a aussi un deuxième point qui rend calloc()plus lent que malloc(): la multiplication pour la taille. calloc()est nécessaire pour utiliser une multiplication générique (si size_test 64 bits même l'opération très coûteuse 64 bits * 64 bits = 64 bits) tandis que le malloc () aura souvent une constante de temps de compilation.
Patrick Schlüter
4
glibc calloc a quelques astuces pour décider comment effacer le plus efficacement le morceau retourné, par exemple parfois seulement une partie de celui-ci a besoin d'être effacé, et aussi un effacement déroulé jusqu'à 9 * sizeof (size_t). La mémoire est de la mémoire, l'effacer de 3 octets à la fois ne sera pas plus rapide simplement parce que vous allez ensuite l'utiliser pour la conserver struct foo { char a,b,c; };. callocvaut toujours mieux que malloc+ memset, si vous voulez toujours effacer toute la mallocrégion ed. calloca également une vérification minutieuse mais efficace des débordements int dans les éléments size *.
Peter Cordes
8
Différence 1:
malloc() alloue généralement le bloc de mémoire et il est un segment de mémoire initialisé.
calloc() alloue le bloc de mémoire et initialise tout le bloc de mémoire à 0.
Différence 2:
Si vous considérez la malloc()syntaxe, elle ne prendra qu'un seul argument. Considérez l'exemple suivant ci-dessous:
Et pourquoi gardez-vous data_type et cast_type différents?
Épuisé
7
Il y a deux différences.
Tout d'abord, c'est dans le nombre d'arguments. malloc()prend un seul argument (mémoire requise en octets), alors qu'il a calloc()besoin de deux arguments.
Deuxièmement, malloc()n'initialise pas la mémoire allouée, tout en calloc()initialisant la mémoire allouée à ZERO.
calloc()alloue une zone mémoire, la longueur sera le produit de ses paramètres. callocremplit la mémoire de ZÉRO et renvoie un pointeur sur le premier octet. S'il ne parvient pas à localiser suffisamment d'espace, il renvoie un NULLpointeur.
malloc()alloue un seul bloc de mémoire de REQUSTED SIZE et renvoie un pointeur sur le premier octet. S'il ne parvient pas à localiser la quantité de mémoire requise, il renvoie un pointeur nul.
Syntaxe: ptr_var=(cast_type *)malloc(Size_in_bytes);
la malloc()fonction prend un argument, qui est le nombre d'octets à allouer, tandis que la calloc()fonction prend deux arguments, l'un étant le nombre d'éléments, et l'autre étant le nombre d'octets à allouer pour chacun de ces éléments. En outre, calloc()initialise l'espace alloué à des zéros, alors malloc()qu'il ne le fait pas.
malloc()et calloc()sont des fonctions de la bibliothèque standard C qui permettent l'allocation dynamique de la mémoire, ce qui signifie qu'elles permettent toutes les deux l'allocation de la mémoire pendant l'exécution.
Il y a principalement deux différences entre les deux:
Comportement: malloc()alloue un bloc de mémoire, sans l'initialiser, et la lecture du contenu de ce bloc entraînera des valeurs inutiles. calloc(), d'autre part, alloue un bloc de mémoire et l'initialise à zéro, et évidemment la lecture du contenu de ce bloc se traduira par des zéros.
Syntaxe: malloc()prend 1 argument (la taille à allouer) et calloc()prend deux arguments (nombre de blocs à allouer et taille de chaque bloc).
La valeur de retour des deux est un pointeur sur le bloc de mémoire alloué, en cas de succès. Sinon, NULL sera renvoyé, indiquant l'échec de l'allocation de mémoire.
Exemple:
int*arr;// allocate memory for 10 integers with garbage values
arr =(int*)malloc(10*sizeof(int));// allocate memory for 10 integers and sets all of them to 0
arr =(int*)calloc(10,sizeof(int));
Les mêmes fonctionnalités que celles qui calloc()peuvent être obtenues en utilisant malloc()et memset():
// allocate memory for 10 integers with garbage values
arr=(int*)malloc(10*sizeof(int));// set all of them to 0
memset(arr,0,10*sizeof(int));
Notez qu'il malloc()est de préférence utilisé calloc()car il est plus rapide. Si vous souhaitez initialiser les valeurs à zéro, utilisez calloc()plutôt.
Une différence pas encore mentionnée: taille limite
void *malloc(size_t size)ne peut allouer que jusqu'à SIZE_MAX.
void *calloc(size_t nmemb, size_t size);peut allouer environ SIZE_MAX*SIZE_MAX.
Cette capacité n'est pas souvent utilisée dans de nombreuses plates-formes avec adressage linéaire. De tels systèmes se limitent calloc()à nmemb * size <= SIZE_MAX.
Considérons un type de 512 octets appelé disk_sectoret le code veut utiliser beaucoup de secteurs. Ici, le code ne peut utiliser que des SIZE_MAX/sizeof disk_sectorsecteurs.
Maintenant, si un tel système peut fournir une allocation aussi importante, c'est une autre affaire. La plupart aujourd'hui ne le feront pas. Pourtant, cela s'est produit pendant de nombreuses années quand il SIZE_MAXétait 65535. Compte tenu de la loi de Moore , soupçonnez que cela se produira vers 2030 avec certains modèles de SIZE_MAX == 4294967295mémoire et des pools de mémoire dans les 100 Go.
Généralement, size_t sera capable de contenir la taille du plus grand type d'objet qu'un programme pourrait gérer. Un système où size_t est de 32 bits est peu susceptible de pouvoir gérer une allocation supérieure à 4294967295 octets, et un système qui serait capable de gérer des allocations de cette taille ferait presque certainement size_tplus de 32 bits. La seule question est de savoir si l'utilisation callocavec des valeurs dont le produit dépasse SIZE_MAXpeut être invoquée pour produire zéro plutôt que de renvoyer un pointeur vers une allocation plus petite.
supercat
Soyez d'accord sur votre généralisation , mais la spécification C permet des calloc()allocations supérieures SIZE_MAX. Cela s'est produit dans le passé avec 16 bits size_tet comme la mémoire continue de diminuer, je ne vois aucune raison pour que cela ne se produise pas, même si ce n'est pas courant .
chux
1
La norme C permet au code de demander une allocation dont la taille dépasse SIZE_MAX. Cela n'exige certainement pas qu'il y ait des circonstances dans lesquelles une telle allocation pourrait réussir; Je ne suis pas sûr qu'il y ait un avantage particulier à exiger que les implémentations qui ne peuvent pas gérer de telles allocations doivent retourner NULL(d'autant plus qu'il est courant pour certaines implémentations d'avoir des mallocpointeurs de retour vers un espace qui n'est pas encore validé et qui pourrait ne pas être disponible lorsque le code essaie réellement d'utiliser il).
supercat
De plus, là où il pouvait y avoir dans le passé des systèmes dont la plage d'adressage disponible dépassait le plus grand entier représentable, je ne vois aucune possibilité réaliste que cela se reproduise, car cela nécessiterait une capacité de stockage de milliards de gigaoctets. Même si la loi de Moore continuait de s'appliquer, passer du point où 32 bits cesserait d'être suffisant au point où 64 bits cesserait d'être suffisant prendrait deux fois plus de temps que de passer du point où 16 bits suffisait au point où 32 n'était pas 't.
supercat
1
Pourquoi une mise en œuvre qui peut accueillir une allocation unique supérieure à la 4G ne se définirait-elle size_tpas uint64_t?
supercat du
2
Nombre de blocs:
malloc () affecte un seul bloc de mémoire demandée,
calloc () affecte plusieurs blocs de la mémoire demandée
Initialisation:
malloc () - n'efface pas et n'initialise pas la mémoire allouée.
calloc () - initialise la mémoire allouée par zéro.
Vitesse:
malloc () est rapide.
calloc () est plus lent que malloc ().
Arguments et syntaxe:
malloc () prend 1 argument:
octets
Le nombre d'octets à allouer
calloc () prend 2 arguments:
longueur
le nombre de blocs de mémoire à allouer
octets
le nombre d'octets à allouer à chaque bloc de mémoire
Manière d'allocation de mémoire:
La fonction malloc attribue de la mémoire de la «taille» souhaitée à partir du tas disponible.
La fonction calloc attribue à la mémoire la taille de ce qui est égal à 'num * size'.
Signification du nom:
Le nom malloc signifie "allocation de mémoire".
Le nom calloc signifie "allocation contiguë".
malloc
familleptr = calloc(MAXELEMS, sizeof(*ptr));
Réponses:
calloc()
vous donne un tampon zéro initialisé, tout enmalloc()
laissant la mémoire non initialisée.Pour les allocations importantes, la plupart des
calloc
implémentations sous les OS traditionnels obtiendront des pages à zéro connu de l'OS (par exemple via POSIXmmap(MAP_ANONYMOUS)
ou WindowsVirtualAlloc
), il n'a donc pas besoin de les écrire dans l'espace utilisateur. C'est ainsi que la normalemalloc
obtient plus de pages du système d'exploitation;calloc
profite simplement de la garantie de l'OS.Cela signifie que la
calloc
mémoire peut toujours être «propre» et allouée paresseusement, et la copie sur écriture mappée sur une page physique partagée de zéros à l'échelle du système. (En supposant un système avec mémoire virtuelle.)Certains compilateurs peuvent même optimiser malloc + memset (0) en calloc pour vous, mais vous devez utiliser explicitement calloc si vous voulez que la mémoire soit lue
0
.Si vous ne lirez jamais la mémoire avant de l'écrire, utilisez-la
malloc
afin qu'elle puisse (potentiellement) vous donner de la mémoire sale à partir de sa liste libre interne au lieu d'obtenir de nouvelles pages du système d'exploitation. (Ou au lieu de mettre à zéro un bloc de mémoire sur la liste gratuite pour une petite allocation).Les implémentations intégrées de
calloc
peuvent laisser àcalloc
lui-même la mémoire zéro s'il n'y a pas de système d'exploitation, ou ce n'est pas un système d'exploitation multi-utilisateurs sophistiqué qui met à zéro les pages pour arrêter les fuites d'informations entre les processus.Sur Linux embarqué, malloc pourrait
mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS)
, qui n'est activé que pour certains noyaux intégrés car il n'est pas sécurisé sur un système multi-utilisateur.la source
calloc
n'est pas nécessairement plus cher, car OS peut faire quelques trucs pour l'accélérer. Je sais que FreeBSD, quand il obtient un temps processeur inactif, l'utilise pour exécuter un processus simple qui fait le tour et met à zéro les blocs de mémoire désalloués, et marque les blocs ainsi traités avec un indicateur. Ainsi, lorsque vous le faitescalloc
, il essaie d'abord de trouver l'un de ces blocs pré-mis à zéro et de vous le donner - et il en trouvera probablement un.Une différence moins connue est que dans les systèmes d'exploitation avec une allocation de mémoire optimiste, comme Linux, le pointeur renvoyé par
malloc
n'est pas soutenu par de la mémoire réelle jusqu'à ce que le programme le touche réellement.calloc
touche en effet la mémoire (il y écrit des zéros) et donc vous serez sûr que le système d'exploitation sauvegarde l'allocation avec de la RAM réelle (ou swap). C'est aussi pourquoi il est plus lent que malloc (non seulement il doit le mettre à zéro, le système d'exploitation doit également trouver une zone de mémoire appropriée en échangeant éventuellement d'autres processus)Voir par exemple cette question SO pour plus de détails sur le comportement de malloc
la source
calloc
pas besoin d'écrire des zéros. Si le bloc alloué se compose principalement de nouvelles pages nulles fournies par le système d'exploitation, il peut les laisser intactes. Bien sûr, cela nécessitecalloc
d'être réglé sur le système d'exploitation plutôt que sur une fonction de bibliothèque génériquemalloc
. Ou, un implémenteur pourrait fairecalloc
comparer chaque mot à zéro avant de le mettre à zéro. Cela ne ferait pas gagner de temps, mais cela éviterait de salir les nouvelles pages.dlmalloc
implémentations similaires ignorentmemset
si le bloc a été obtenu via demmap
nouvelles pages anonymes (ou équivalent). Habituellement, ce type d'allocation est utilisé pour les gros morceaux, à partir de 256 Ko environ. Je ne connais aucune implémentation qui fasse la comparaison avec zéro avant d'écrire zéro à part la mienne.omalloc
saute également lememset
;calloc
n'a jamais besoin de toucher à des pages qui ne sont pas déjà utilisées par l'application (cache de pages). Cependant, lescalloc
implémentations extrêmement primitives diffèrent.Un avantage souvent négligé
calloc
est que (implémentations conformes de) il vous aidera à vous protéger contre les vulnérabilités de débordement d'entier. Comparer:contre.
Le premier pourrait entraîner une petite allocation et des dépassements de tampon ultérieurs, s'il
count
est supérieur àSIZE_MAX/sizeof *bar
. Ce dernier échouera automatiquement dans ce cas car un objet de cette taille ne peut pas être créé.Bien sûr, vous devrez peut-être être à la recherche d'implémentations non conformes qui ignorent simplement la possibilité de débordement.
la source
char
n'est pas un débordement mais plutôt une conversion définie par l'implémentation lors de la réaffectation du résultat dans unchar
objet.size_t
64 bits donc ce n'est pas un problème", c'est une façon de penser erronée qui va conduire à des bugs de sécurité.size_t
est un type abstrait qui représente des tailles, et il n'y a aucune raison de penser que le produit arbitraire d'un nombre 32 bits et d'unsize_t
(remarque:sizeof *bar
pourrait en principe être supérieur à 2 ^ 32 sur une implémentation C 64 bits!) s'intègresize_t
.La documentation fait ressembler le calloc à malloc, qui initialise simplement la mémoire à zéro; ce n'est pas la principale différence! L'idée de calloc est d'abstraire la sémantique de copie sur écriture pour l'allocation de mémoire. Lorsque vous allouez de la mémoire avec calloc, tout est mappé sur la même page physique qui est initialisée à zéro. Lorsqu'une des pages de la mémoire allouée est écrite dans une page physique est allouée. Ceci est souvent utilisé pour créer des tables de hachage ÉNORMES, par exemple car les parties de hachage vides ne sont pas soutenues par une mémoire supplémentaire (pages); ils pointent joyeusement vers la page unique initialisée à zéro, qui peut même être partagée entre les processus.
Toute écriture sur une adresse virtuelle est mappée sur une page, si cette page est la page zéro, une autre page physique est allouée, la page zéro y est copiée et le flux de contrôle est renvoyé au processus client. Cela fonctionne de la même manière que les fichiers mappés en mémoire, la mémoire virtuelle, etc. fonctionnent .. il utilise la pagination.
Voici une histoire d'optimisation sur le sujet: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
la source
Il n'y a aucune différence dans la taille du bloc de mémoire alloué.
calloc
remplit simplement le bloc de mémoire avec un motif physique de zéro. Dans la pratique, on suppose souvent que les objets situés dans le bloc de mémoire alloué aveccalloc
ont une valeur initiale comme s'ils avaient été initialisés avec un littéral0
, c'est-à-dire que les entiers devraient avoir la valeur de0
, les variables à virgule flottante - la valeur de0.0
, les pointeurs - la pointeur nul appropriée , etc.Du point de vue pédant cependant,
calloc
(ainsi quememset(..., 0, ...)
) n'est garanti que pour initialiser correctement (avec des zéros) les objets de typeunsigned char
. Tout le reste n'est pas garanti d'être correctement initialisé et peut contenir ce qu'on appelle une représentation d'interruption , ce qui provoque un comportement non défini. En d'autres termes, pour tout type autre queunsigned char
le motif tout-à-zéro susmentionné, il pourrait représenter une valeur illégale, une représentation d'interruption.Plus tard, dans l'un des rectificatifs techniques à la norme C99, le comportement a été défini pour tous les types d'entiers (ce qui est logique). Autrement dit, dans le langage C actuel, vous ne pouvez initialiser que les types entiers avec
calloc
(etmemset(..., 0, ...)
). L'utiliser pour initialiser autre chose dans le cas général conduit à un comportement indéfini, du point de vue du langage C.En pratique,
calloc
ça marche, comme nous le savons tous :), mais c'est à vous de décider si vous souhaitez l'utiliser (compte tenu de ce qui précède). Personnellement, je préfère l'éviter complètement, utiliser à lamalloc
place et effectuer ma propre initialisation.Enfin, un autre détail important est celui qui
calloc
est nécessaire pour calculer la taille finale du bloc en interne , en multipliant la taille des éléments par le nombre d'éléments. Ce faisant, vouscalloc
devez surveiller les éventuels débordements arithmétiques. Il en résultera une allocation infructueuse (pointeur nul) si la taille de bloc demandée ne peut pas être calculée correctement. Pendant ce temps, votremalloc
version n'essaie pas de surveiller les débordements. Il allouera une certaine quantité de mémoire "imprévisible" en cas de débordement.la source
memset(p, v, n * sizeof type);
problème car iln * sizeof type
peut déborder. Je suppose que je devrai utiliser unefor(i=0;i<n;i++) p[i]=v;
boucle pour un code robuste.n
éléments existe là où un élément a la taillesizeof type
, iln*sizeof type
ne peut pas déborder, car la taille maximale de tout objet doit être inférieure àSIZE_MAX
.SIZE_MAX
, mais il n'y a pas de tableaux ici. Le pointeur renvoyé parcalloc()
peut pointer vers la mémoire allouée qui dépasseSIZE_MAX
. De nombreuses implémentations limitent le produit des 2 argumentscalloc()
àSIZE_MAX
, mais la spécification C n'impose pas cette limite.extrait d'un article Benchmarking fun with calloc () and zero pages on Georg Hager's Blog
la source
calloc
est généralementmalloc+memset
à 0Il est généralement légèrement préférable d'utiliser
malloc+memset
explicitement, surtout lorsque vous faites quelque chose comme:C'est mieux car il
sizeof(Item)
est connu du compilateur au moment de la compilation et le compilateur le remplacera dans la plupart des cas par les meilleures instructions possibles pour mettre à zéro la mémoire. D'un autre côté, si celamemset
se produitcalloc
, la taille du paramètre de l'allocation n'est pas compilée dans lecalloc
code et réelmemset
est souvent appelé, qui contiendrait généralement du code pour effectuer le remplissage octet par octet jusqu'à la limite longue, puis cycle pour remplir la mémoire ensizeof(long)
morceaux et enfin le remplissage octet par octet de l'espace restant. Même si l'allocateur est suffisamment intelligent pour en appeler,aligned_memset
ce sera toujours une boucle générique.Une exception notable serait lorsque vous faites malloc / calloc d'une très grande partie de la mémoire (quelques power_of_two kilobytes), auquel cas l'allocation peut être effectuée directement à partir du noyau. Comme les noyaux de système d'exploitation mettent généralement à zéro toute la mémoire qu'ils donnent pour des raisons de sécurité, un calloc suffisamment intelligent peut simplement le renvoyer sans mise à zéro supplémentaire. Encore une fois - si vous allouez simplement quelque chose que vous savez petit, vous pourriez être mieux avec malloc + memset en termes de performances.
la source
calloc()
plus lent quemalloc()
: la multiplication pour la taille.calloc()
est nécessaire pour utiliser une multiplication générique (sisize_t
est 64 bits même l'opération très coûteuse 64 bits * 64 bits = 64 bits) tandis que le malloc () aura souvent une constante de temps de compilation.struct foo { char a,b,c; };
.calloc
vaut toujours mieux quemalloc
+memset
, si vous voulez toujours effacer toute lamalloc
région ed.calloc
a également une vérification minutieuse mais efficace des débordements int dans les éléments size *.Différence 1:
malloc()
alloue généralement le bloc de mémoire et il est un segment de mémoire initialisé.calloc()
alloue le bloc de mémoire et initialise tout le bloc de mémoire à 0.Différence 2:
Si vous considérez la
malloc()
syntaxe, elle ne prendra qu'un seul argument. Considérez l'exemple suivant ci-dessous:Ex: si vous souhaitez allouer 10 blocs de mémoire pour le type int,
Si vous considérez la
calloc()
syntaxe, cela prendra 2 arguments. Considérez l'exemple suivant ci-dessous:Ex: si vous voulez allouer 10 blocs de mémoire pour le type int et initialiser tout cela à ZERO,
Similarité:
Les deux
malloc()
etcalloc()
renverront void * par défaut s'ils ne sont pas transtypés.!la source
Il y a deux différences.
Tout d'abord, c'est dans le nombre d'arguments.
malloc()
prend un seul argument (mémoire requise en octets), alors qu'il acalloc()
besoin de deux arguments.Deuxièmement,
malloc()
n'initialise pas la mémoire allouée, tout encalloc()
initialisant la mémoire allouée à ZERO.calloc()
alloue une zone mémoire, la longueur sera le produit de ses paramètres.calloc
remplit la mémoire de ZÉRO et renvoie un pointeur sur le premier octet. S'il ne parvient pas à localiser suffisamment d'espace, il renvoie unNULL
pointeur.Syntaxe:
ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
ieptr_var=(type *)calloc(n,s);
malloc()
alloue un seul bloc de mémoire de REQUSTED SIZE et renvoie un pointeur sur le premier octet. S'il ne parvient pas à localiser la quantité de mémoire requise, il renvoie un pointeur nul.Syntaxe:
ptr_var=(cast_type *)malloc(Size_in_bytes);
lamalloc()
fonction prend un argument, qui est le nombre d'octets à allouer, tandis que lacalloc()
fonction prend deux arguments, l'un étant le nombre d'éléments, et l'autre étant le nombre d'octets à allouer pour chacun de ces éléments. En outre,calloc()
initialise l'espace alloué à des zéros, alorsmalloc()
qu'il ne le fait pas.la source
La
calloc()
fonction qui est déclarée dans l'en-<stdlib.h>
tête offre quelques avantages par rapport à lamalloc()
fonction.la source
malloc()
etcalloc()
sont des fonctions de la bibliothèque standard C qui permettent l'allocation dynamique de la mémoire, ce qui signifie qu'elles permettent toutes les deux l'allocation de la mémoire pendant l'exécution.Leurs prototypes sont les suivants:
Il y a principalement deux différences entre les deux:
Comportement:
malloc()
alloue un bloc de mémoire, sans l'initialiser, et la lecture du contenu de ce bloc entraînera des valeurs inutiles.calloc()
, d'autre part, alloue un bloc de mémoire et l'initialise à zéro, et évidemment la lecture du contenu de ce bloc se traduira par des zéros.Syntaxe:
malloc()
prend 1 argument (la taille à allouer) etcalloc()
prend deux arguments (nombre de blocs à allouer et taille de chaque bloc).La valeur de retour des deux est un pointeur sur le bloc de mémoire alloué, en cas de succès. Sinon, NULL sera renvoyé, indiquant l'échec de l'allocation de mémoire.
Exemple:
Les mêmes fonctionnalités que celles qui
calloc()
peuvent être obtenues en utilisantmalloc()
etmemset()
:Notez qu'il
malloc()
est de préférence utilisécalloc()
car il est plus rapide. Si vous souhaitez initialiser les valeurs à zéro, utilisezcalloc()
plutôt.la source
Une différence pas encore mentionnée: taille limite
void *malloc(size_t size)
ne peut allouer que jusqu'àSIZE_MAX
.void *calloc(size_t nmemb, size_t size);
peut allouer environSIZE_MAX*SIZE_MAX
.Cette capacité n'est pas souvent utilisée dans de nombreuses plates-formes avec adressage linéaire. De tels systèmes se limitent
calloc()
ànmemb * size <= SIZE_MAX
.Considérons un type de 512 octets appelé
disk_sector
et le code veut utiliser beaucoup de secteurs. Ici, le code ne peut utiliser que desSIZE_MAX/sizeof disk_sector
secteurs.Considérez ce qui suit qui permet une allocation encore plus importante.
Maintenant, si un tel système peut fournir une allocation aussi importante, c'est une autre affaire. La plupart aujourd'hui ne le feront pas. Pourtant, cela s'est produit pendant de nombreuses années quand il
SIZE_MAX
était 65535. Compte tenu de la loi de Moore , soupçonnez que cela se produira vers 2030 avec certains modèles deSIZE_MAX == 4294967295
mémoire et des pools de mémoire dans les 100 Go.la source
size_t
plus de 32 bits. La seule question est de savoir si l'utilisationcalloc
avec des valeurs dont le produit dépasseSIZE_MAX
peut être invoquée pour produire zéro plutôt que de renvoyer un pointeur vers une allocation plus petite.calloc()
allocations supérieuresSIZE_MAX
. Cela s'est produit dans le passé avec 16 bitssize_t
et comme la mémoire continue de diminuer, je ne vois aucune raison pour que cela ne se produise pas, même si ce n'est pas courant .SIZE_MAX
. Cela n'exige certainement pas qu'il y ait des circonstances dans lesquelles une telle allocation pourrait réussir; Je ne suis pas sûr qu'il y ait un avantage particulier à exiger que les implémentations qui ne peuvent pas gérer de telles allocations doivent retournerNULL
(d'autant plus qu'il est courant pour certaines implémentations d'avoir desmalloc
pointeurs de retour vers un espace qui n'est pas encore validé et qui pourrait ne pas être disponible lorsque le code essaie réellement d'utiliser il).size_t
pasuint64_t
?Nombre de blocs:
malloc () affecte un seul bloc de mémoire demandée,
calloc () affecte plusieurs blocs de la mémoire demandée
Initialisation:
malloc () - n'efface pas et n'initialise pas la mémoire allouée.
calloc () - initialise la mémoire allouée par zéro.
Vitesse:
malloc () est rapide.
calloc () est plus lent que malloc ().
Arguments et syntaxe:
malloc () prend 1 argument:
octets
calloc () prend 2 arguments:
longueur
Manière d'allocation de mémoire:
La fonction malloc attribue de la mémoire de la «taille» souhaitée à partir du tas disponible.
La fonction calloc attribue à la mémoire la taille de ce qui est égal à 'num * size'.
Signification du nom:
Le nom malloc signifie "allocation de mémoire".
Le nom calloc signifie "allocation contiguë".
la source