82 votes

Pourquoi malloc initialise-t-il les valeurs à 0 dans gcc?

Peut-être que c'est différent d'une plateforme à une autre, mais

quand je compile avec gcc et exécuter le code ci-dessous, j'obtiens 0 à chaque fois, dans mon ubuntu 11.10.

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

int main()
{
    double *a = (double*) malloc(sizeof(double)*100)
    printf("%f", *a);
}

Pourquoi ne malloc se comporter comme cela, même si il n'y a calloc?

N'est-ce pas dire qu'il n'y est pas désirée surcharge de performance juste pour initialiser les valeurs à 0, même si vous ne voulez pas qu'il soit parfois?


EDIT: Oh, mon exemple précédent n'a pas été initiazling, mais qui est arrivé à utiliser des "frais" de bloc.

Ce que j'ai précisément cherchais pourquoi il l'initialise lorsqu'il alloue un gros bloc:

int main()
{
    int *a = (int*) malloc(sizeof(int)*200000);
    a[10] = 3;
    printf("%d", *(a+10));

    free(a);

    a = (double*) malloc(sizeof(double)*200000);
    printf("%d", *(a+10));
}

OUTPUT: 3
        0 (initialized)

Mais merci pour remarquer qu'il y est une des raisons de SÉCURITÉ, lorsque mallocing! (Jamais pensé à ça). Assurez-vous qu'il a à initialiser à zéro lors de l'attribution des frais de bloc, ou le grand bloc.

188voto

Mysticial Points 180300

Réponse Courte:

Il n'a pas, il arrive juste à être de zéro dans votre cas.
(Également votre cas de test ne montre pas que les données sont à zéro. Il ne s'affiche que si un élément est égale à zéro.)


Réponse Longue:

Lorsque vous appelez malloc(), l'une des deux choses vont se produire:

  1. Il recycle mémoire qui a été allouée précédent et libéré à partir du même processus.
  2. Il demande une nouvelle page(s) du système d'exploitation.

Dans le premier cas, la mémoire contient les données des restes de la précédente allocations. Afin de ne pas être égale à zéro. C'est le cas d'habitude lors de la réalisation de petites allocations.

Dans le second cas, la mémoire sera de l'OS. Cela se produit lorsque le programme s'exécute hors de la mémoire - ou lorsque vous demandez une très large répartition. (comme c'est le cas dans l'exemple)

Le hic, c'est la Mémoire à venir de l'OS sera remis à zéro pour la sécurité .*

Lorsque le système d'exploitation vous donne de la mémoire, il aurait pu être libéré à partir d'un autre processus. De sorte que la mémoire peut contenir des informations confidentielles telles qu'un mot de passe. Afin de vous éviter la lecture de ces données, le système d'exploitation zéro avant qu'il le donne à vous.

*Je note que la norme ne dit rien à ce sujet. C'est strictement un OS comportement. Donc, cette mise à zéro peut ou peut ne pas être présent sur les systèmes où la sécurité n'est pas une préoccupation.


Pour donner plus d'une performance historique de cette:

@R. mentionne dans les commentaires, cette réduction à zéro est pourquoi vous devriez toujours utiliser calloc() au lieu de malloc() + memset(). calloc() peuvent profiter de ce fait pour éviter un distinct memset().


D'autre part, cette réduction à zéro est parfois un goulot d'étranglement des performances. Dans certaines applications numériques (comme la out-of-lieu de la FFT), vous devez allouer un énorme morceau de rayer de la mémoire. L'utiliser pour effectuer quel que soit l'algorithme, puis gratuit.

Dans ces cas, la réduction à zéro est inutile et les montants de pur frais généraux.

L'exemple le plus extrême que j'ai vu est un de 20 secondes réinitialisation de la surcharge d'un 70-deuxième opération de 48 GO de zéro de la mémoire tampon. (Environ 30% de frais généraux.) (Accordée, la machine avait un manque de bande passante de la mémoire.)

La solution évidente est de simplement réutiliser la mémoire manuellement. Mais qui nécessite souvent une rupture avec ces interfaces. (surtout si elle fait partie d'une routine de bibliothèque)

21voto

hugomg Points 29789

L'OS est généralement claire de la mémoire de frais les pages qu'il envoie à votre processus de sorte qu'il ne peut pas regarder une ancienne processus de données. Cela signifie que la première fois que vous initialisez une variable (ou malloc quelque chose), il sera souvent zéro, mais si jamais vous la réutilisation de la mémoire (en libérant et le malloc-ing de nouveau, par exemple), alors tous les paris sont éteints.

Cette incohérence est précisément la raison pour laquelle les variables non initialisées sont très difficiles à trouver bug.


Comme pour les indésirables de la performance des frais généraux, en évitant quelconque comportement est probablement plus important. Tout ce petit boost de performance, vous pouvez gagner dans ce cas de ne pas compenser le disque dur pour trouver les bogues que vous aurez à traiter avec si quelqu'un modifie légèrement les codes (casser les hypothèses précédentes) ou des ports sur un autre système (où les hypothèses pourrait avoir été invalide en premier lieu).

19voto

Dan Aloni Points 2198

Pourquoi supposez-vous que malloc() initialise à zéro? Il se trouve juste à être le premier appel à malloc() résultats dans un appel à l' sbrk ou mmap des appels système, qui attribuent une page de mémoire à partir de l'OS. Le système d'exploitation est tenu de fournir initialisé à zéro de la mémoire pour des raisons de sécurité (dans le cas contraire, les données provenant d'autres processus devient visible!). De sorte que vous peut penser qu' - les OS des pertes de temps de réinitialisation de la page. Mais non! Sous Linux, il existe un régime spécial à l'échelle de singleton page appelée le 'zéro' la page et que la page va être substitués comme Copy-on-Write, ce qui signifie que c'est seulement quand vous avez réellement écrire sur cette page, le système d'exploitation allouer une autre page et l'initialiser. Donc j'espère que cela répond à votre question concernant les performances. La pagination de la mémoire de modèle permet l'utilisation de la mémoire pour être sorte de paresseux en soutenant la capacité de plusieurs de cartographie de la même page, plus la capacité de gérer le cas lorsque le premier à écrire se produit.

Si vous appelez free(), glibc allocateur sera de retour la région à ses listes libres, et lorsqu' malloc() est appelée de nouveau, vous pourriez obtenir la même région, mais sale avec les données précédentes. Finalement, free() le risque de retourner la mémoire à l'OS par l'appel des appels système à nouveau.

Notez que l' glibc page de man sur malloc() strictement dit que la mémoire n'est pas effacée par le "contrat" sur l'API, vous ne pouvez pas supposer qu'il ne se purifient. Voici l'original de l'extrait:

malloc() alloue size octets, et renvoie un pointeur vers la mémoire allouée.
La mémoire n'est pas effacée. Si la taille est 0, alors la fonction malloc() renvoie NULL, ou une valeur de pointeur unique, qui peut ensuite être passé avec succès à free().

Si vous le souhaitez, vous pouvez lire plus au sujet de ce que la documentation si vous êtes inquiet au sujet de la performance ou d'autres effets secondaires.

16voto

Praetorian Points 47122

J'ai modifié votre exemple pour qu'il contienne 2 allocations identiques. Maintenant, il est facile de voir que malloc n'initialise pas la mémoire à zéro.

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

int main(void)
{
    {
      double *a = malloc(sizeof(double)*100);
      *a = 100;
      printf("%f\n", *a);
      free(a);
    }
    {
      double *a = malloc(sizeof(double)*100);
      printf("%f\n", *a);
      free(a);
    }

    return 0;
}
 

Sortie avec gcc 4.3.4

 100.000000
100.000000
 

2voto

GeorgeAl Points 2926

La norme n'impose pas à malloc() d'initialiser les valeurs à zéro. Il arrive tout simplement sur votre plate-forme qu'elle soit définie sur zéro ou sur zéro au moment précis où vous avez lu cette valeur.

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