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?

7voto

spenceryue Punkte 350

Es gibt sogar einen Abschnitt in der OSTEP Online-Lehrbuch für einen Grundkurs in Betriebssystemen, in dem genau Ihre Frage behandelt wird.

Der entsprechende Abschnitt ist "Vergessen, um das Gedächtnis zu befreien" in der Kapitel Speicher-API auf Seite 6, die die folgende Erklärung enthält:

In manchen Fällen mag es sinnvoll erscheinen, free() nicht aufzurufen. Für Beispiel: Ihr Programm ist kurzlebig und wird bald beendet; in diesem Fall, Wenn der Prozess stirbt, räumt das Betriebssystem alle ihm zugewiesenen Seiten auf und daher wird kein Speicherleck entstehen. Auch wenn dies sicherlich "funktioniert" (siehe die Anmerkung auf Seite 7), aber es ist wahrscheinlich eine schlechte Angewohnheit, also seien Sie vorsichtig bei der Wahl einer solchen Strategie

Dieser Auszug steht im Zusammenhang mit der Einführung des Konzepts des virtuellen Speichers. Im Wesentlichen erklären die Autoren an dieser Stelle des Buches, dass eines der Ziele eines Betriebssystems darin besteht, den Speicher zu "virtualisieren", d. h. jedes Programm glauben zu lassen, dass es Zugriff auf einen sehr großen Speicheradressraum hat.

Hinter den Kulissen übersetzt das Betriebssystem "virtuelle Adressen", die der Benutzer sieht, in tatsächliche Adressen, die auf physischen Speicher verweisen.

Die gemeinsame Nutzung von Ressourcen wie z. B. des physischen Speichers erfordert jedoch, dass das Betriebssystem den Überblick darüber behält, welche Prozesse ihn nutzen. Wenn also ein Prozess beendet wird, liegt es im Rahmen der Möglichkeiten und der Designziele des Betriebssystems, den Speicher des Prozesses zurückzufordern, so dass es den Speicher neu verteilen und mit anderen Prozessen teilen kann.


EDITAR: Die in dem Auszug erwähnte Randbemerkung ist nachstehend wiedergegeben.

ASIDE: WARUM NACH BEENDIGUNG DES PROZESSES KEIN SPEICHER VERLOREN GEHT

Wenn Sie ein kurzlebiges Programm schreiben, können Sie etwas Platz zuweisen mit malloc() . Das Programm läuft und ist kurz vor dem Abschluss: Ist es Notwendigkeit zum Aufruf free() ein paar Mal kurz vor dem Verlassen? Es scheint zwar Es scheint zwar falsch zu sein, dies nicht zu tun, aber es geht keine Erinnerung im eigentlichen Sinne "verloren". Der Grund ist einfach: Es gibt zwei Ebenen der Speicherverwaltung im System. Die erste Ebene der Speicherverwaltung wird vom Betriebssystem durchgeführt, das Speicher an Prozesse verteilt, wenn diese laufen, und ihn zurücknimmt, wenn Prozesse beendet werden (oder anderweitig sterben). Die zweite Ebene der Verwaltung findet innerhalb jedes Prozesses statt, zum Beispiel innerhalb des Heaps, wenn Sie malloc() y free() . Auch wenn Sie nicht anrufen free() (und damit Leck Speicher im Heap), wird das Betriebssystem den gesamten Speicher des Prozesses zurückfordern Prozesses (einschließlich der Seiten für Code, Stack und - hier relevant - Heap) Heap), wenn das Programm beendet ist. Egal, wie der Zustand Ihres Heaps in Ihrem Adressraum, das Betriebssystem holt sich alle diese Seiten zurück zurück, wenn der Prozess stirbt, wodurch sichergestellt wird, dass kein Speicher verloren geht, obwohl die Tatsache, dass Sie ihn nicht freigegeben haben.

Bei kurzlebigen Programmen verursacht das Entweichen von Speicherplatz also oft keine Betriebsprobleme (auch wenn es als schlechter Stil angesehen werden kann). Wenn Sie einen langlaufenden Server schreiben (z. B. einen Webserver oder ein Datenbankmanagementsystem Datenbankmanagementsystem, das nie beendet wird), ist ausgelaufener Speicher ein viel größeres Problem, und wird schließlich zu einem Absturz führen, wenn der Anwendung der Speicher ausgeht. Speicher geht. Und natürlich ist ein Speicherleck ein noch größeres Problem innerhalb eines bestimmten Programms: des Betriebssystems selbst. Das zeigt uns einmal mehr wieder einmal: Diejenigen, die den Kernel-Code schreiben, haben den härtesten Job von allen...

von Seite 7 von Speicher-API Kapitel von

Betriebssysteme: Drei einfache Teile
Remzi H. Arpaci-Dusseau und Andrea C. Arpaci-Dusseau Arpaci-Dusseau Bücher März, 2015 (Version 0.90)

5voto

Kyle Cronin Punkte 74993

Es gibt keine echte Gefahr Aber wenn Sie einen Zeiger auf einen Speicherblock einem anderen Speicherblock zuweisen, ohne den ersten Block freizugeben, ist der erste Block nicht mehr zugänglich, nimmt aber immer noch Platz ein. Dies nennt man ein Speicherleck, und wenn Sie dies regelmäßig tun, wird Ihr Prozess immer mehr Speicher verbrauchen und anderen Prozessen Systemressourcen entziehen.

Wenn der Prozess nur von kurzer Dauer ist, können Sie oft damit auskommen, da der gesamte zugewiesene Speicher vom Betriebssystem zurückerobert wird, wenn der Prozess beendet ist, aber ich würde empfehlen, sich anzugewöhnen, den gesamten Speicher freizugeben, den Sie nicht mehr benötigen.

4voto

ken_you_not Punkte 63

Es kommt auf den Umfang des Projekts an, an dem Sie arbeiten. Im Zusammenhang mit Ihrer Frage, und ich meine nur Ihre Frage, spielt es keine Rolle.

Für eine weitere Erklärung (optional), einige Szenarien, die ich aus dieser ganzen Diskussion bemerkt habe, ist wie folgt:

(1) - Wenn Sie in einer eingebetteten Umgebung arbeiten, in der Sie sich nicht darauf verlassen können, dass das Haupt-Betriebssystem den Speicher für Sie zurückfordert, sollten Sie ihn freigeben, da Speicherlecks das Programm wirklich zum Absturz bringen können, wenn sie unbemerkt bleiben.

(2) - Wenn Sie an einem persönlichen Projekt arbeiten, bei dem Sie es nicht an andere weitergeben wollen, können Sie es weglassen (vorausgesetzt, Sie verwenden es auf dem Hauptbetriebssystem) oder es aus Gründen der "besten Praktiken" einbeziehen.

(3) - Wenn Sie an einem Projekt arbeiten und planen, es als Open-Source-Projekt zu veröffentlichen, müssen Sie mehr über Ihre Zielgruppe recherchieren und herausfinden, ob die Freigabe des Speichers die bessere Wahl wäre.

(4) - Wenn Sie eine große Bibliothek haben und Ihr Publikum nur aus den wichtigsten Betriebssystemen besteht, dann brauchen Sie sie nicht freizugeben, da ihre Betriebssysteme ihnen dabei helfen werden. In der Zwischenzeit können Ihre Bibliotheken/Programme durch den Verzicht auf das Freigeben dazu beitragen, die Gesamtleistung zu verbessern, da das Programm nicht jede Datenstruktur schließen muss, wodurch sich die Zeit bis zum Herunterfahren verlängert (stellen Sie sich vor, Sie müssten sehr lange warten, bis Sie Ihren Computer herunterfahren, bevor Sie das Haus verlassen...)

Ich könnte immer wieder aufzählen, welchen Kurs Sie belegen sollten, aber letztlich hängt es davon ab, was Sie mit Ihrem Programm erreichen wollen. Das Freigeben von Speicher wird in manchen Fällen als gute Praxis angesehen, in anderen nicht so sehr, so dass es letztendlich von der spezifischen Situation abhängt, in der Sie sich befinden, und davon, die richtigen Fragen zur richtigen Zeit zu stellen. Viel Glück!

3voto

Michael Punkte 52790

Sie haben recht, der Speicher wird automatisch freigegeben, wenn der Prozess beendet wird. Manche Leute bemühen sich, beim Beenden des Prozesses keine umfangreichen Aufräumarbeiten durchzuführen, da alles an das Betriebssystem zurückgegeben wird. Während Ihr Programm läuft, sollten Sie jedoch ungenutzten Speicher freigeben. Wenn Sie das nicht tun, kann es passieren, dass Sie irgendwann keinen Speicher mehr haben oder dass Sie zu viel Speicher auslagern, wenn Ihr Arbeitsbereich zu groß wird.

3voto

Uri Punkte 86472

In dieser Hinsicht haben Sie völlig recht. In kleinen, trivialen Programmen, in denen eine Variable bis zum Ende des Programms existieren muss, bringt es keinen wirklichen Vorteil, den Speicher freizugeben.

Tatsächlich war ich einmal an einem Projekt beteiligt, bei dem jede Ausführung des Programms sehr komplex, aber relativ kurzlebig war, und die Entscheidung lautete, nur den zugewiesenen Speicher beizubehalten und das Projekt nicht durch Fehler beim Freigeben zu destabilisieren.

In den meisten Programmen ist dies jedoch keine wirkliche Option, oder es kann dazu führen, dass der Speicher nicht mehr ausreicht.

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