665 Stimmen

Was passiert WIRKLICH, wenn man nach malloc nicht frei gibt, bevor das Programm beendet wird?

Uns allen wurde beigebracht, dass man jeden zugewiesenen Zeiger freigeben MUSS. Ich bin allerdings ein wenig neugierig, was es wirklich kostet, wenn man den Speicher nicht freigibt. In einigen offensichtlichen Fällen, etwa wenn malloc() innerhalb einer Schleife oder eines Teils einer Thread-Ausführung aufgerufen wird, ist es sehr wichtig, den Speicher freizugeben, damit keine Speicherlecks entstehen. Aber betrachten Sie die folgenden zwei Beispiele:

Erstens, wenn ich einen Code habe, der in etwa so aussieht:

int main()
{
    char *a = malloc(1024);
    /* Do some arbitrary stuff with 'a' (no alloc functions) */
    return 0;
}

Was ist das wirkliche Ergebnis hier? Ich denke, dass der Prozess stirbt und dann der Heap-Speicherplatz sowieso weg ist, so dass es keinen Schaden gibt, wenn der Aufruf von free (Ich erkenne jedoch an, wie wichtig es ist, sie trotzdem zu haben, um sie zu schließen, zu warten und um eine gute Praxis zu haben). Liege ich mit dieser Überlegung richtig?

Zweitens: Nehmen wir an, ich habe ein Programm, das ein wenig wie eine Shell funktioniert. Benutzer können Variablen deklarieren wie aaa = 123 und diese werden zur späteren Verwendung in einer dynamischen Datenstruktur gespeichert. Es liegt auf der Hand, dass Sie eine Lösung verwenden, die eine *alloc-Funktion aufruft (Hashmap, verknüpfte Liste oder etwas Ähnliches). Für diese Art von Programm macht es keinen Sinn, nach dem Aufruf von malloc weil diese Variablen während der Ausführung des Programms jederzeit vorhanden sein müssen und es keine gute Möglichkeit gibt (die ich sehen kann), dies mit statisch zugewiesenem Speicherplatz zu implementieren. Ist es schlechtes Design, um einen Haufen Speicher zu haben, der zugewiesen wird, aber nur als Teil der Prozessbeendigung freigegeben wird? Wenn ja, was ist die Alternative?

462voto

Paul Tomblin Punkte 172816

So gut wie jedes moderne Betriebssystem stellt den gesamten zugewiesenen Speicherplatz wieder her, nachdem ein Programm beendet wurde. Die einzige Ausnahme, die mir einfällt, ist vielleicht so etwas wie Palm OS, wo der statische Speicher des Programms und der Laufzeitspeicher so ziemlich dasselbe sind, so dass ein Nichtfreigeben dazu führen könnte, dass das Programm mehr Speicherplatz benötigt. (Ich spekuliere hier nur.)

Im Allgemeinen schadet es also nicht, abgesehen von den Laufzeitkosten, die dadurch entstehen, dass man mehr Speicherplatz als nötig hat. In dem von Ihnen angeführten Beispiel möchten Sie den Speicher für eine Variable, die möglicherweise verwendet wird, so lange behalten, bis sie gelöscht wird.

Es gehört jedoch zum guten Ton, den Speicher freizugeben, sobald er nicht mehr benötigt wird, und alles, was noch vorhanden ist, beim Beenden des Programms zu löschen. Es ist eher eine Übung darin, zu wissen, welchen Speicher man benutzt, und zu überlegen, ob man ihn noch braucht. Wenn Sie nicht aufpassen, könnten Sie Speicherlecks haben.

Andererseits hat die ähnliche Ermahnung, Ihre Dateien beim Beenden zu schließen, ein viel konkreteres Ergebnis - wenn Sie das nicht tun, werden die Daten, die Sie in die Dateien geschrieben haben, möglicherweise nicht geleert, oder, wenn es sich um eine temporäre Datei handelt, werden sie möglicherweise nicht gelöscht, wenn Sie fertig sind. Außerdem sollten die Transaktionen von Datenbank-Handles bestätigt und anschließend geschlossen werden, wenn Sie mit ihnen fertig sind. Wenn Sie eine objektorientierte Sprache wie C++ oder Objective C verwenden, bedeutet das Nichtfreigeben eines Objekts, wenn Sie damit fertig sind, dass der Destruktor nie aufgerufen wird und alle Ressourcen, für die die Klasse verantwortlich ist, möglicherweise nicht aufgeräumt werden.

130voto

compie Punkte 9739

Ja, Sie haben Recht, Ihr Beispiel richtet keinen Schaden an (zumindest nicht auf den meisten modernen Betriebssystemen). Der gesamte von Ihrem Prozess belegte Speicher wird vom Betriebssystem wiederhergestellt, sobald der Prozess beendet ist.

Quelle: Zuteilung und GC-Mythen (PostScript-Alarm!)

Zuweisungsmythos 4: Programme, die keinen Speicherplatz sammeln sollten immer den gesamten Speicher freigeben den sie zuweisen.

Die Wahrheit: Ausgelassene Deallokationen in häufig ausgeführtem Code verursachen wachsende Lecks. Sie sind selten akzeptabel. aber Programme, die den meisten zugewiesenen Speicher behalten, bis Programmende behalten, sind oft besser ohne eine zwischenzeitliche Freigabe. Malloc ist viel einfacher zu implementieren, wenn es kein free gibt.

In den meisten Fällen, Freigeben von Speicherplatz kurz vor dem Programmende ist sinnlos. Das Betriebssystem wird es ohnehin zurückfordern. Freie berührt und blättert in den toten Objekte, das Betriebssystem nicht.

Konsequenz: Seien Sie vorsichtig mit "Leck Detektoren", die Zuweisungen zählen. Manche "Lecks" sind gut!

Trotzdem sollten Sie wirklich versuchen, alle Speicherlecks zu vermeiden!

Zweite Frage: Ihr Entwurf ist in Ordnung. Wenn Sie etwas speichern müssen, bis Ihre Anwendung beendet ist, dann ist es in Ordnung, dies mit dynamischer Speicherzuweisung zu tun. Wenn Sie die erforderliche Größe im Voraus nicht kennen, können Sie keinen statisch zugewiesenen Speicher verwenden.

76voto

Trevor Boyd Smith Punkte 16590

\=== Was ist mit zukunftssicher y Code-Wiederverwendung ? ===

Wenn Sie nicht Wenn Sie den Code zum Freigeben der Objekte schreiben, können Sie den Code nur dann sicher verwenden, wenn Sie sich darauf verlassen können, dass der Speicher durch das Beenden des Prozesses freigegeben wird, d. h. bei kleinen Projekten zur einmaligen Verwendung oder zum "Wegwerfen". [1] Projekte)... wo Sie wissen, wann der Prozess beendet sein wird.

Wenn Sie tun den Code schreiben, der den gesamten dynamisch zugewiesenen Speicher freigibt, dann ist der Code zukunftssicher und kann von anderen in einem größeren Projekt verwendet werden.


[1] über "Wegwerfprojekte". Code, der in "Wegwerf"-Projekten verwendet wird, kann nicht einfach weggeworfen werden. Das nächste, was Sie wissen, ist, dass zehn Jahre vergangen sind und Ihr "Wegwerf"-Code immer noch verwendet wird).

Ich habe eine Geschichte über einen Mann gehört, der aus Spaß Code geschrieben hat, damit seine Hardware besser funktioniert. Er sagte " nur ein Hobby, wird nicht groß und professionell sein ". Jahre später verwenden viele Leute seinen "Hobby"-Code.

61voto

DigitalRoss Punkte 138823

Sie haben recht, es wird kein Schaden angerichtet, und es ist schneller, einfach auszusteigen.

Hierfür gibt es verschiedene Gründe:

  • Alle Desktop- und Serverumgebungen geben bei exit() einfach den gesamten Speicherplatz frei. Sie kennen keine programminternen Datenstrukturen wie z.B. Heaps.

  • Fast alle free() Implementierungen Niemals ohnehin Speicher an das Betriebssystem zurückgeben.

  • Noch wichtiger ist, dass es eine Zeitverschwendung ist, wenn es direkt vor exit() geschieht. Beim Beenden werden Speicherseiten und Swap Space einfach freigegeben. Im Gegensatz dazu verbrennt eine Reihe von free()-Aufrufen CPU-Zeit und kann zu Paging-Operationen auf der Festplatte, Cache-Misses und Cache-Evakuierungen führen.

Bezüglich der Möglichkeit der künftigen Wiederverwendung von Code zur Rechtfertigung der Gewissheit von sinnlosen Operationen: Das ist eine Überlegung, aber wohl nicht die Agil Weise. YAGNI!

46voto

dhein Punkte 6063

Ich bin völlig anderer Meinung als alle, die sagen, dass OP richtig ist oder dass es keinen Schaden gibt.

Alle sprechen von modernen und/oder älteren Betriebssystemen.

Was aber, wenn ich mich in einer Umgebung befinde, in der ich einfach kein Betriebssystem habe? Wo es nichts gibt?

Stellen Sie sich vor, Sie verwenden nun Thread-ähnliche Unterbrechungen und weisen Speicher zu. In der C-Norm ISO/IEC:9899 ist die Lebensdauer des Speichers wie folgt angegeben:

7.20.3 Funktionen zur Speicherverwaltung

1 Die Reihenfolge und Zusammengehörigkeit des durch aufeinanderfolgende Aufrufe der Funktionen calloc, malloc und realloc ist nicht spezifiziert. Der Zeiger, der zurückgegeben wird, wenn die Zuweisung zurückgegebene Zeiger ist in geeigneter Weise ausgerichtet, so dass er einem Zeiger auf einen beliebigen Objekttyp zugewiesen werden kann zugewiesen und dann für den Zugriff auf ein solches Objekt oder ein Array solcher Objekte in dem zugewiesenen Speicherplatz verwendet werden kann zugreifen kann (bis der Speicherplatz explizit freigegeben wird). Die Lebensdauer eines zugewiesenen Objekts erstreckt sich von der Zuweisung bis zur Freigabe.[...]

Es muss also nicht unbedingt so sein, dass die Umwelt die befreiende Aufgabe für Sie übernimmt. Andernfalls würde es dem letzten Satz hinzugefügt werden: "Oder bis das Programm beendet wird."

Mit anderen Worten: Speicher nicht freizugeben ist nicht nur eine schlechte Praxis. Es erzeugt nicht portablen und nicht C-konformen Code. Was zumindest als 'korrekt angesehen werden kann, wenn das Folgende: [...], von der Umgebung unterstützt wird'.

Aber in Fällen, in denen Sie überhaupt kein Betriebssystem haben, erledigt niemand die Arbeit für Sie (Ich weiß, dass man auf eingebetteten Systemen im Allgemeinen keinen Speicher zuweist und neu zuweist, aber es gibt Fälle, in denen man das vielleicht möchte).

Also in allgemeinem Plain C (als das der OP getaggt ist) zu sprechen, ist dies einfach produzieren fehlerhafte und nicht portablen Code.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X