Angenommen, ich habe den folgenden C-Code:
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
Wenn ich dieses C-Programm kompiliere und ausführe, dh nachdem ich Speicherplatz zugewiesen habe, wird der von mir zugewiesene Speicher nach dem Beenden der Anwendung und dem Beenden des Prozesses weiterhin zugewiesen (dh im Grunde genommen Speicherplatz beanspruchend)?
c
memory-management
Andreas Grech
quelle
quelle
Antworten:
Dies hängt vom Betriebssystem ab. Die Mehrheit der modernen (und aller wichtigen) Betriebssysteme gibt Speicher frei, der vom Programm nicht freigegeben wird, wenn es endet.
Sich darauf zu verlassen ist eine schlechte Praxis und es ist besser, sie explizit freizugeben. Das Problem ist nicht nur, dass Ihr Code schlecht aussieht. Möglicherweise möchten Sie Ihr kleines Programm in ein größeres, lang laufendes Programm integrieren. Dann, eine Weile später, müssen Sie Stunden damit verbringen, Speicherlecks aufzuspüren.
Wenn Sie sich auf eine Funktion eines Betriebssystems verlassen, ist der Code auch weniger portabel.
quelle
Im Allgemeinen bereinigen moderne Allzweckbetriebssysteme nach Beendigung von Prozessen . Dies ist erforderlich, da die Alternative darin besteht, dass das System im Laufe der Zeit Ressourcen verliert und einen Neustart aufgrund von Programmen erfordert, die schlecht geschrieben sind oder einfach selten auftretende Fehler aufweisen, durch die Ressourcen verloren gehen.
Es kann aus verschiedenen Gründen eine gute Praxis sein, wenn Ihr Programm seine Ressourcen ohnehin explizit freigibt, z. B.:
Hier ist jedoch ein Grund, das Freigeben von Speicher zu überspringen: effizientes Herunterfahren . Angenommen, Ihre Anwendung enthält einen großen Cache im Speicher. Wenn es beim Beenden die gesamte Cache-Struktur durchläuft und Stück für Stück freigibt, dient dies keinem nützlichen Zweck und verschwendet Ressourcen. Betrachten Sie insbesondere den Fall, in dem die Speicherseiten, die Ihren Cache enthalten, vom Betriebssystem auf die Festplatte ausgelagert wurden. Wenn Sie durch die Struktur gehen und sie freigeben, bringen Sie alle diese Seiten auf einmal wieder in den Speicher , verschwenden viel Zeit und Energie ohne wirklichen Nutzen und führen möglicherweise sogar dazu, dass andere Programme auf dem System ausgetauscht werden!
Als verwandtes Beispiel gibt es Hochleistungsserver, bei denen für jede Anforderung ein Prozess erstellt und nach Abschluss beendet wird. auf diese Weise sie müssen nicht einmal Speicher verfolgen Zuordnung , und nie überhaupt eine Befreiung oder Garbage Collection zu tun, da alles nur zurück in die am Ende des Prozesses freier Speicher Betriebssystem verschwindet. (Dasselbe kann innerhalb eines Prozesses mit einem benutzerdefinierten Speicherzuweiser ausgeführt werden, erfordert jedoch eine sehr sorgfältige Programmierung; im Wesentlichen muss man sich im Betriebssystemprozess eine eigene Vorstellung von „Lightweight-Prozessen“ machen.)
quelle
Ich entschuldige mich dafür, dass ich so lange nach dem letzten Beitrag in diesem Thread gepostet habe.
Ein zusätzlicher Punkt. Nicht alle Programme erreichen anmutige Exits. Abstürze und Strg-Cs usw. führen dazu, dass ein Programm unkontrolliert beendet wird. Wenn Ihr Betriebssystem Ihren Heap nicht freigeben, Ihren Stack bereinigen, statische Variablen usw. löschen würde, würde Ihr System möglicherweise aufgrund von Speicherlecks oder Schlimmerem abstürzen.
Abgesehen davon haben Abstürze / Unterbrechungen in Ubuntu und ich vermute, dass alle anderen modernen Betriebssysteme Probleme mit "behandelten" Ressourcen haben. Sockets, Dateien, Geräte usw. können "offen" bleiben, wenn ein Programm endet / abstürzt Es empfiehlt sich auch, alles im Rahmen Ihrer Bereinigung vor dem ordnungsgemäßen Beenden mit einem "Handle" oder "Deskriptor" zu schließen.
Ich entwickle derzeit ein Programm, das Sockets stark nutzt. Wenn ich in einem Hang stecken bleibe, muss ich die Strg-C-Taste drücken, um meine Steckdosen zu stranden. Ich habe einen std :: vector hinzugefügt, um eine Liste aller geöffneten Sockets und einen Sigaction-Handler zu sammeln, der Sigint und Sigterm abfängt. Der Handler geht die Liste durch und schließt die Sockets. Ich habe vor, vor dem Werfen eine ähnliche Bereinigungsroutine durchzuführen, die zu einer vorzeitigen Beendigung führt.
Möchte jemand diesen Entwurf kommentieren?
quelle
Was hier ( in einem modernen Betriebssystem ) passiert , ist, dass Ihr Programm in einem eigenen "Prozess" ausgeführt wird. Dies ist eine Betriebssystementität, die über einen eigenen Adressraum, Dateideskriptoren usw. verfügt. Ihre
malloc
Aufrufe weisen Speicher vom "Heap" oder nicht zugewiesenen Speicherseiten zu, die Ihrem Prozess zugewiesen sind.Wenn Ihr Programm wie in diesem Beispiel endet, werden alle Ihrem Prozess zugewiesenen Ressourcen einfach vom Betriebssystem recycelt / heruntergefahren. Im Falle des Speichers werden alle Ihnen zugewiesenen Speicherseiten einfach als "frei" markiert und für die Verwendung anderer Prozesse recycelt. Seiten sind ein untergeordnetes Konzept als das, was Malloc handhabt. Infolgedessen werden die Besonderheiten von Malloc / Free einfach weggespült, wenn das Ganze aufgeräumt wird.
Es ist das moralische Äquivalent dazu, dass Sie sich nicht die Mühe machen, jede Datei einzeln zu löschen, wenn Sie mit Ihrem Laptop fertig sind und ihn einem Freund geben möchten. Sie formatieren einfach die Festplatte.
Wie alle anderen Antwortenden bemerken, ist es jedoch keine gute Praxis, sich darauf zu verlassen:
quelle
Ja. Das Betriebssystem bereinigt Ressourcen. Nun ... alte Versionen von NetWare haben es nicht getan.
Bearbeiten: Wie San Jacinto betonte, gibt es sicherlich Systeme (außer NetWare), die dies nicht tun. Selbst in Wegwerfprogrammen versuche ich, mir die Gewohnheit zu machen, alle Ressourcen freizugeben, nur um die Gewohnheit aufrechtzuerhalten.
quelle
Ja, das Betriebssystem gibt den gesamten Speicher frei, wenn der Prozess endet.
quelle
malloc
kann nur versprechen, was C mit dem Speicher machen wird; Von Natur aus garantiert C nicht viel in Bezug auf Verhalten außerhalb von C selbst. Wenn die App unerwartet stirbt, sind alle Versprechen, die die Laufzeitbibliothek gemacht hat, null und nichtig, da es nicht mehr lebendig ist, sie zu erfüllen.Es hängt davon ab, dass Betriebssysteme es normalerweise für Sie bereinigen. Wenn Sie jedoch beispielsweise an eingebetteter Software arbeiten, wird es möglicherweise nicht freigegeben.
Stellen Sie einfach sicher, dass Sie es freigeben. Dies kann Ihnen später viel Zeit sparen, wenn Sie es in ein großes Projekt integrieren möchten.
quelle
Das hängt wirklich vom Betriebssystem ab, aber für alle Betriebssysteme, auf die Sie jemals stoßen werden, verschwindet die Speicherzuordnung, wenn der Prozess beendet wird.
quelle
Ich denke, direkte Befreiung ist am besten. Undefiniertes Verhalten ist das Schlimmste. Wenn Sie also Zugriff haben, während es noch in Ihrem Prozess definiert ist, gibt es viele gute Gründe, die die Leute dafür angegeben haben.
Wo oder ob ich das in W98 gefunden habe, war die eigentliche Frage 'wann' (ich habe keinen Beitrag gesehen, der dies betont). Ein kleines Vorlagenprogramm (für MIDI-SysEx-Eingaben unter Verwendung verschiedener malloc'd Leerzeichen) würde Speicher im WM_DESTROY-Bit des WndProc freigeben, aber als ich dies in ein größeres Programm transplantierte, stürzte es beim Beenden ab. Ich nahm an, dass dies bedeutete, dass ich versuchte, das freizugeben, was das Betriebssystem bereits während einer größeren Bereinigung freigegeben hatte. Wenn ich es auf WM_CLOSE gemacht habe, dann DestroyWindow () genannt, hat alles gut funktioniert, sofort sauberes Beenden.
Dies ist zwar nicht genau dasselbe wie bei MIDI-Puffern, es besteht jedoch eine Ähnlichkeit darin, dass es am besten ist, den Prozess intakt zu halten, vollständig zu bereinigen und dann zu beenden. Mit bescheidenen Speicherblöcken ist dies sehr schnell. Ich fand heraus, dass viele kleine Puffer im Betrieb und bei der Bereinigung schneller arbeiteten als weniger große.
Es kann Ausnahmen geben, wie jemand sagte, wenn vermieden wird, große Speicherblöcke aus einer Auslagerungsdatei auf der Festplatte zurückzuholen, aber selbst dies kann minimiert werden, indem mehr und kleinere zugewiesene Speicherplätze beibehalten werden.
quelle