2010-09-10 12 views
11

realloc wird verwendet, um den Speicher dynamisch neu zuzuweisen.Was würde Realloc tun, wenn es keinen sequentiellen Speicherraum gibt?

Angenommen, ich habe 7 Bytes mit der malloc Funktion zugewiesen und jetzt möchte ich es auf 30 Bytes erweitern.

Was passiert im Hintergrund, wenn es im Speicher keinen fortlaufenden (fortlaufend in einer Zeile) Speicherplatz von 30 Bytes gibt?

Gibt es einen Fehler oder wird Speicher in Teilen zugeordnet?

Antwort

11

realloc Arbeiten hinter den Kulissen in etwa wie folgt aus:

  • Wenn es hinter dem aktuellen Block genügend freier Speicherplatz vorhanden ist, um die Anforderung zu erfüllen, den aktuellen Block erstrecken und einen Zeiger auf den Anfang des Blocks zurückkehren .
  • Sonst, wenn an anderer Stelle ein ausreichend großer freier Block vorhanden ist, dann diesen Block zuweisen, die Daten aus dem alten Block kopieren, den alten Block freigeben und einen Zeiger an den Anfang des neuen Blocks zurückgeben
  • Rückgabe NULL.

So können Sie für Fehler testen, indem Sie für NULL testen, aber bewusst sein, dass Sie nicht überschreiben die alten Zeiger zu früh:

int* p = malloc(x); 
/* ... */ 
p = realloc(p, y); /* WRONG: Old pointer lost if realloc fails: memory leak! */ 
/* Correct way: */ 
{ 
    int* temp = realloc(p, y); 
    if (NULL == temp) 
    { 
    /* Handle error; p is still valid */ 
    } 
    else 
    { 
    /* p now possibly points to deallocated memory. Overwrite it with the pointer 
     to the new block, to start using that */ 
    p = temp; 
    } 
} 
+0

Ist das 'Realloc' für alle Implementierungen? –

+0

@CoolGuy: Einige Implementierungen könnten diesen ersten Schritt zur Erweiterung des aktuellen Blocks nicht ausführen (können), aber ansonsten ist dies das beobachtbare Verhalten von 'realloc' für alle Implementierungen. –

1

Vom man page:

realloc() gibt einen Zeiger auf den neu zugeordneten Speicher, der in geeigneter Weise für jede Art von variable ausgerichtet ist und kann von ptr oder NULL, wenn die unterschiedlich sein Anfrage schlägt fehl.

Mit anderen Worten, um einen Fehler zu erkennen, überprüfen Sie einfach, ob das Ergebnis NULL war.

EDIT: Wie im Kommentar erwähnt, wenn der Aufruf fehlschlägt, wird der ursprüngliche Speicher nicht freigegeben.

+2

Es lohnt sich, von der man-Seite zu notieren: Wenn realloc() fehlschlägt, bleibt der ursprüngliche Block unberührt; Es ist nicht freigegeben oder verschoben. –

6

realloc wird nur gelingen, wenn es einen zusammenhängenden ("sequentiellen" in Ihren Worten) Speicherblock zurückgeben kann. Wenn kein solcher Block existiert, gibt er NULL zurück.

+4

@Mark - Originalspeicher bleibt unverändert. Ein häufiger Fehler in diesem Zusammenhang ist 'x = realloc (x)' - Sie müssen 'newX = realloc (x)' tun, um zu vermeiden, dass das ursprüngliche x bei einem Fehler verloren geht. –

+0

@Steve Townsend - Nur wenn es keinen Ritus gibt? Wenn es erfolgreich ist, gibt es den ursprünglichen Zeiger frei. Und wer markiert auf dieser Seite? O_o –

+0

Ich denke, es gab einen Fehler. Der erste Kommentar wurde vom Benutzer sharptooth gezeigt und nun ändert sich der Kommentar, obwohl beide an Mark adressiert sind. War das ein Fehler? :-P –

1

Im Allgemeinen hängt es von der Implementierung ab. Auf x86 (-64) Linux glaube ich, dass der Standard doug lea malloc-Algorithmus immer ein Minimum einer Standard-x86-Seite (4096 Bytes) zuweist, so dass für das oben beschriebene Szenario nur die Grenzen zurückgesetzt würden, um die zusätzlichen Bytes aufzunehmen. Wenn es darum geht, einen Puffer von 7 Bytes auf PAGE_SIZE + 1 neu zuzuweisen, glaube ich, dass es versuchen wird, die nächste zusammenhängende Seite zuzuordnen, falls verfügbar.

Worth Lesen der folgenden, wenn Sie auf Linux entwickelst:

standardmäßig Linux folgt eine optimistische Speicherzuordnungsstrategie. Dies bedeutet, dass wenn malloc() nicht NULL zurückgibt, es keine Garantie gibt, dass der Speicher wirklich verfügbar ist. Dies ist ein wirklich Bad Bug. Falls sich herausstellt, dass das System nicht genügend Speicher hat, werden ein oder mehrere Prozesse von dem berüchtigten OOM-Killer getötet. Falls Linux unter Umständen verwendet, wo es weniger wünschenswert, plötzlich zu verlieren einige zufällig ausgewählte Prozesse sein würde, und darüber hinaus die Kernel-Version ist ausreichend neu, kann man dieses Overcommit Verhalten mit einem Befehl wie ausschalten:

# echo 2 > /proc/sys/vm/overcommit_memory 

Siehe auch das Kernel-Dokumentationsverzeichnis, die Dateien vm/overcommit-accounting und sysctl/vm.txt.

0

FreeBSD und Mac OS X die reallocf() Funktion, die den übergebenen Zeiger freigibt, wenn der angeforderte Speicher nicht zugeordnet werden kann (siehe man realloc).

+0

Anstatt dies zu verwenden, wäre es viel sinnvoller, nur eine eigene Funktion zu schreiben, um dies zu tun, wenn Sie dieses Verhalten wirklich wollen. Aber ich kann mir nicht vorstellen, dass es sehr nützlich ist - es wirft wahrscheinlich wertvolle Daten weg. –