Warum initialisiert malloc die Werte in gcc auf 0?

 C Programming >> C-Programmierung >  >> Tags >> GCC
Warum initialisiert malloc die Werte in gcc auf 0?


Vielleicht ist es von Plattform zu Plattform unterschiedlich, aber


Wenn ich mit gcc kompiliere und den folgenden Code ausführe, erhalte ich jedes Mal 0 in meinem Ubuntu 11.10.


#include <stdio.h>
#include <stdlib.h>
int main()
{
double *a = malloc(sizeof(double)*100)
printf("%f", *a);
}

Warum verhalten sich malloc so, obwohl es calloc gibt?


Bedeutet das nicht, dass es einen unerwünschten Leistungsaufwand gibt, nur um die Werte auf 0 zu initialisieren, auch wenn Sie es manchmal nicht wollen?



BEARBEITEN:Oh, mein vorheriges Beispiel hat nicht initialisiert, sondern zufällig einen "frischen" Block verwendet.


Was ich genau gesucht habe, war, warum es initialisiert wird, wenn es einen großen Block zuweist:


int main()
{
int *a = malloc(sizeof(int)*200000);
a[10] = 3;
printf("%d", *(a+10));
free(a);
a = malloc(sizeof(double)*200000);
printf("%d", *(a+10));
}
OUTPUT: 3
0 (initialized)

Aber danke für den Hinweis, dass es beim Mallocing einen SICHERHEITSgrund gibt! (Habe niemals drüber nachgedacht). Sicher, es muss auf Null initialisiert werden, wenn ein frischer Block oder der große Block zugewiesen wird.


Antworten:


Kurze Antwort:


Das tut es nicht, es ist in Ihrem Fall einfach null.
(Auch Ihr Testfall zeigt nicht, dass die Daten Null sind. Es zeigt nur, wenn ein Element Null ist.)



Lange Antwort:


Wenn Sie malloc() anrufen , wird eines von zwei Dingen passieren:



  1. Es recycelt Speicher, der zuvor zugewiesen und von demselben Prozess freigegeben wurde.

  2. Es fordert neue Seite(n) vom Betriebssystem an.


Im ersten Fall enthält der Speicher Daten, die von früheren Zuordnungen übrig geblieben sind. Es wird also nicht null sein. Dies ist der übliche Fall, wenn kleine Allokationen durchgeführt werden.


Im zweiten Fall stammt der Speicher vom Betriebssystem. Dies geschieht, wenn dem Programm der Speicher ausgeht - oder wenn Sie eine sehr große Zuweisung anfordern. (wie in Ihrem Beispiel)


Hier ist der Haken:Speicher, der vom Betriebssystem kommt, wird aus Sicherheitsgründen auf Null gesetzt Gründen.*


Wenn das Betriebssystem Ihnen Speicher zur Verfügung stellt, könnte es von einem anderen Prozess befreit worden sein. Dieser Speicher könnte also sensible Informationen wie ein Passwort enthalten. Um zu verhindern, dass Sie solche Daten lesen, wird das Betriebssystem sie auf Null setzen, bevor es sie Ihnen gibt.


*Ich stelle fest, dass der C-Standard nichts darüber aussagt. Dies ist ausschließlich ein Betriebssystemverhalten. Daher kann diese Nullstellung auf Systemen vorhanden sein oder auch nicht, bei denen die Sicherheit keine Rolle spielt.



Um mehr über die Leistung zu erfahren:


Als @R. erwähnt in den Kommentaren, diese Nullung ist der Grund, warum Sie immer calloc() verwenden sollten statt malloc() + memset() . calloc() können diese Tatsache ausnutzen, um ein separates memset() zu vermeiden .



Andererseits ist dieses Nullstellen manchmal ein Leistungsengpass. Bei einigen numerischen Anwendungen (wie der Out-of-Place-FFT) müssen Sie einen großen Teil des Scratch-Speichers zuweisen. Verwenden Sie es, um einen beliebigen Algorithmus auszuführen, und geben Sie es dann frei.


In diesen Fällen ist das Nullstellen unnötig und stellt einen reinen Overhead dar.


Das extremste Beispiel, das ich gesehen habe, ist ein 20-sekündiger Zeroing-Overhead für einen 70-sekündigen Vorgang mit einem 48-GB-Scratch-Puffer. (Ungefähr 30 % Overhead.)
(Zugegeben:Die Maschine hatte einen Mangel an Speicherbandbreite.)


Die offensichtliche Lösung besteht darin, den Speicher einfach manuell wiederzuverwenden. Doch dafür müssen oft etablierte Schnittstellen durchbrochen werden. (insbesondere wenn es Teil einer Bibliotheksroutine ist)