Ist es jemals akzeptabel, dass in Ihrer C- oder C ++ - Anwendung ein Speicherverlust auftritt ?
Was ist, wenn Sie Speicher zuweisen und ihn bis zur letzten Codezeile in Ihrer Anwendung verwenden (z. B. den Destruktor eines globalen Objekts)? Ist es in Ordnung, dem Betriebssystem zu vertrauen, dass es Ihren Speicher für Sie freigibt, wenn Ihre Anwendung beendet wird (unter Windows, Mac und Linux), solange der Speicherverbrauch nicht mit der Zeit zunimmt? Würden Sie dies sogar als echten Speicherverlust betrachten, wenn der Speicher kontinuierlich verwendet würde, bis er vom Betriebssystem freigegeben wurde?
Was wäre, wenn eine Bibliothek eines Drittanbieters Ihnen diese Situation aufzwingen würde? Würden Sie sich weigern, diese Bibliothek eines Drittanbieters zu verwenden, egal wie großartig sie sonst sein könnte?
Ich sehe nur einen praktischen Nachteil, nämlich dass diese gutartigen Lecks bei Tools zur Erkennung von Speicherlecks als falsch positiv angezeigt werden.
quelle
Antworten:
Nein.
Als Profis sollten wir uns nicht die Frage stellen: "Ist es jemals in Ordnung, dies zu tun?" sondern "Gibt es jemals einen guten Grund, dies zu tun?" Und "das Aufspüren dieses Speicherlecks ist ein Schmerz" ist kein guter Grund.
Ich mag es, die Dinge einfach zu halten. Und die einfache Regel ist, dass mein Programm keine Speicherlecks haben sollte.
Das macht auch mein Leben einfach. Wenn ich einen Speicherverlust feststelle, eliminiere ich ihn, anstatt eine aufwändige Entscheidungsbaumstruktur zu durchlaufen, um festzustellen, ob es sich um einen "akzeptablen" Speicherverlust handelt.
Es ähnelt Compiler-Warnungen. Wird die Warnung für meine spezielle Anwendung schwerwiegend sein? Vielleicht nicht.
Aber letztendlich geht es um professionelle Disziplin. Compiler-Warnungen zu tolerieren und Speicherlecks zu tolerieren, ist eine schlechte Angewohnheit, die mich letztendlich in den Hintern beißen wird.
Wäre es für einen Chirurgen jemals akzeptabel, ein Operationsgerät in einem Patienten zu lassen, um die Dinge auf ein Extrem zu bringen?
Obwohl es möglich ist, dass ein Umstand auftritt, in dem die Kosten / das Risiko für das Entfernen dieses Geräts die Kosten / das Risiko für das Zurücklassen des Geräts übersteigen, und es Umstände geben kann, in denen es harmlos war, wenn ich diese Frage auf SurgeonOverflow.com gesehen habe und wenn ich eine andere Antwort als "Nein" sah, würde dies mein Vertrauen in die Ärzteschaft ernsthaft untergraben.
- -
Wenn mir eine Bibliothek eines Drittanbieters diese Situation aufzwingen würde, würde dies mich dazu bringen, die Gesamtqualität der betreffenden Bibliothek ernsthaft zu vermuten. Es wäre, als würde ich ein Auto testen und ein paar lose Unterlegscheiben und Muttern in einem der Getränkehalter finden - es ist vielleicht keine große Sache für sich, aber es zeigt einen Mangel an Engagement für Qualität, also würde ich Alternativen in Betracht ziehen.
quelle
Ich halte es nicht für einen Speicherverlust, es sei denn, die Menge des "verwendeten" Speichers wächst weiter. Unveröffentlichter Speicher ist zwar nicht ideal, aber kein großes Problem, es sei denn, der erforderliche Speicher wächst ständig.
quelle
Lassen Sie uns zuerst unsere Definitionen richtig machen. Ein Speicherleck ist , wenn der Speicher dynamisch zugeordnet wird , zB mit
malloc()
, und alle Verweise auf den Speicher , ohne die entsprechende freie verloren. Ein einfacher Weg, einen zu machen, ist wie folgt:Beachten Sie, dass jedes Mal um die while (1) -Schleife 1024 (+ Overhead-) Bytes zugewiesen und die neue Adresse vp zugewiesen werden. Es gibt keinen verbleibenden Zeiger auf die vorherigen malloc'ed Blöcke. Dieses Programm wird garantiert ausgeführt, bis der Heap leer ist, und es gibt keine Möglichkeit, den malloc'ed Speicher wiederherzustellen. Der Speicher "leckt" aus dem Haufen, um nie wieder gesehen zu werden.
Wie Sie beschreiben, klingt jedoch
Sie weisen den Speicher zu und arbeiten damit, bis das Programm beendet ist. Dies ist kein Speicherverlust. Das Programm wird dadurch nicht beeinträchtigt, und der gesamte Speicher wird automatisch gelöscht, wenn das Programm beendet wird.
Im Allgemeinen sollten Sie Speicherlecks vermeiden. Erstens, weil wie in der Höhe über Ihnen und beim Tanken im Hangar Speicher, der durchgesickert ist und nicht wiederhergestellt werden kann, nutzlos ist. Zweitens ist es viel einfacher, zu Beginn richtig zu codieren, ohne Speicher zu verlieren, als später einen Speicherverlust zu finden.
quelle
malloc
es eine schlechte Sache ist , wenn Sie zu viel Speicher haben. Es ist immer noch kein Leck . Es ist kein Leck, bis es einmalloc
Speicher ist, auf den die Referenz verloren geht.In der Theorie nein, in der Praxis kommt es darauf an .
Es hängt wirklich davon ab, wie viele Daten das Programm bearbeitet, wie oft das Programm ausgeführt wird und ob es ständig ausgeführt wird oder nicht.
Wenn ich ein schnelles Programm habe, das eine kleine Datenmenge liest, eine Berechnung durchführt und beendet wird, wird ein kleiner Speicherverlust nie bemerkt. Da das Programm nicht sehr lange läuft und nur wenig Speicher benötigt, ist das Leck klein und wird freigegeben, wenn das Programm vorhanden ist.
Wenn ich dagegen ein Programm habe, das Millionen von Datensätzen verarbeitet und lange läuft, kann ein kleiner Speicherverlust den Computer bei genügend Zeit zum Erliegen bringen.
Bei Bibliotheken von Drittanbietern mit Lecks können Sie die Bibliothek reparieren oder eine bessere Alternative finden, wenn sie ein Problem verursachen. Wenn es kein Problem verursacht, ist es dann wirklich wichtig?
quelle
Viele Menschen scheinen den Eindruck zu haben, dass sobald Sie Speicher freigeben, dieser sofort zum Betriebssystem zurückkehrt und von anderen Programmen verwendet werden kann.
Das ist nicht wahr. Betriebssysteme verwalten normalerweise den Speicher auf 4-KB-Seiten.
malloc
und andere Arten der Speicherverwaltung rufen Seiten vom Betriebssystem ab und verwalten sie nach Belieben. Es ist ziemlich wahrscheinlich , dassfree()
wird nicht Seiten an das Betriebssystem zurückzukehren, unter der Annahme , dass Ihr Programm wird später mehr Speicher malloc.Ich sage nicht, dass
free()
niemals Speicher an das Betriebssystem zurückgegeben wird. Dies kann insbesondere dann der Fall sein, wenn Sie große Speicherbereiche freigeben. Aber es gibt keine Garantie.Die wichtige Tatsache: Wenn Sie keinen Speicher mehr freigeben, den Sie nicht mehr benötigen, verbrauchen weitere Mallocs garantiert noch mehr Speicher. Wenn Sie jedoch zuerst freigeben, verwendet malloc möglicherweise stattdessen den freigegebenen Speicher wieder.
Was bedeutet das in der Praxis? Wenn Sie wissen, dass Ihr Programm von nun an keinen Speicher mehr benötigt (z. B. in der Bereinigungsphase), ist das Freigeben von Speicher nicht so wichtig. Wenn das Programm jedoch später möglicherweise mehr Speicher zuweist, sollten Sie Speicherverluste vermeiden - insbesondere solche, die wiederholt auftreten können.
In diesem Kommentar erfahren Sie auch, warum das Freigeben von Speicher kurz vor der Beendigung schlecht ist.
Ein Kommentator schien nicht zu verstehen, dass das Aufrufen
free()
anderen Programmen nicht automatisch erlaubt, den freigegebenen Speicher zu verwenden. Aber das ist der springende Punkt dieser Antwort!Um die Leute zu überzeugen, werde ich ein Beispiel zeigen, in dem free () sehr wenig nützt. Um die Mathematik einfach zu befolgen, werde ich so tun, als ob das Betriebssystem den Speicher auf 4000-Byte-Seiten verwaltet.
Angenommen, Sie weisen zehntausend 100-Byte-Blöcke zu (der Einfachheit halber ignoriere ich den zusätzlichen Speicher, der zum Verwalten dieser Zuordnungen erforderlich wäre). Dies verbraucht 1 MB oder 250 Seiten. Wenn Sie dann 9000 dieser Blöcke zufällig freigeben, bleiben nur 1000 Blöcke übrig - aber sie sind überall verstreut. Statistisch gesehen sind ungefähr 5 der Seiten leer. Die anderen 245 haben jeweils mindestens einen zugewiesenen Block. Das sind 980 KB Speicher, der vom Betriebssystem möglicherweise nicht zurückgefordert werden kann - obwohl Sie jetzt nur noch 100 KB zugewiesen haben!
Auf der anderen Seite können Sie jetzt 9000 weitere Blöcke malloc (), ohne den Speicherplatz zu erhöhen, den Ihr Programm bindet.
Selbst wenn
free()
kann technisch Speicher an das Betriebssystem zurückgeben, kann es nicht tun.free()
muss ein Gleichgewicht zwischen schnellem Betrieb und Speicherplatzersparnis erreichen. Außerdem wird ein Programm, das bereits viel Speicher zugewiesen und dann freigegeben hat, dies wahrscheinlich wieder tun. Ein Webserver muss Anforderung für Anforderung für Anforderung verarbeiten. Es ist sinnvoll, einen "freien" Speicher verfügbar zu halten, damit Sie das Betriebssystem nicht ständig nach Speicher fragen müssen.quelle
Es ist konzeptionell nichts Falsches daran, das Betriebssystem nach dem Ausführen der Anwendung bereinigen zu lassen.
Es hängt wirklich von der Anwendung ab und davon, wie sie ausgeführt wird. Kontinuierlich auftretende Lecks in einer Anwendung, die wochenlang ausgeführt werden muss, müssen behoben werden. Ein kleines Tool, das ein Ergebnis ohne zu hohen Speicherbedarf berechnet, sollte jedoch kein Problem darstellen.
Es gibt einen Grund, warum viele Skriptsprachen keine zyklischen Referenzen sammeln. Aufgrund ihrer Verwendungsmuster ist dies kein wirkliches Problem und würde daher genauso viel Ressourcen verschwenden wie den verschwendeten Speicher.
quelle
Ich glaube, die Antwort ist nein, lassen Sie niemals einen Speicherverlust zu, und ich habe einige Gründe, die ich nicht explizit angegeben habe. Hier gibt es großartige technische Antworten, aber ich denke, die eigentliche Antwort hängt von mehr sozialen / menschlichen Gründen ab.
(Beachten Sie zunächst, dass, wie andere bereits erwähnt haben, ein echtes Leck vorliegt, wenn Ihr Programm zu irgendeinem Zeitpunkt den Überblick über die zugewiesenen Speicherressourcen verliert. In C geschieht dies, wenn Sie
malloc()
auf einen Zeiger verweisen und diesen Zeiger den Gültigkeitsbereich verlassen, ohne a auszuführenfree()
zuerst.)Der wichtige Kern Ihrer Entscheidung hier ist die Gewohnheit. Wenn Sie Code in einer Sprache , die Anwendungen Zeiger, Sie gehen Zeiger verwenden viel . Und Zeiger sind gefährlich; Sie sind der einfachste Weg, um Ihrem Code alle möglichen schwerwiegenden Probleme hinzuzufügen.
Wenn Sie programmieren, werden Sie manchmal am Ball sein und manchmal werden Sie müde oder verrückt oder besorgt sein. Während dieser etwas abgelenkten Zeiten codieren Sie mehr auf dem Autopiloten. Der Autopilot-Effekt unterscheidet nicht zwischen einmaligem Code und einem Modul in einem größeren Projekt. Während dieser Zeit werden die Gewohnheiten, die Sie festlegen, in Ihrer Codebasis landen.
Nein, lassen Sie niemals Speicherlecks zu, aus dem gleichen Grund, aus dem Sie beim Spurwechsel immer noch Ihre toten Winkel überprüfen sollten, auch wenn Sie derzeit das einzige Auto auf der Straße sind. In Zeiten, in denen Ihr aktives Gehirn abgelenkt ist, sind gute Gewohnheiten alles, was Sie vor katastrophalen Fehltritten bewahren kann.
Über das Problem der "Gewohnheit" hinaus sind Zeiger komplex und erfordern oft viel Gehirnleistung, um sie mental zu verfolgen. Es ist am besten, das Wasser nicht zu "trüben", wenn es um die Verwendung von Zeigern geht, insbesondere wenn Sie neu in der Programmierung sind.
Es gibt auch einen sozialeren Aspekt. Durch die ordnungsgemäße Verwendung von
malloc()
undfree()
wird sich jeder, der sich Ihren Code ansieht, wohl fühlen. Sie verwalten Ihre Ressourcen. Wenn Sie dies jedoch nicht tun, werden sie sofort ein Problem vermuten.Vielleicht haben Sie herausgefunden, dass der Speicherverlust in diesem Zusammenhang nichts schadet, aber jeder Betreuer Ihres Codes muss dies auch in seinem Kopf herausfinden, wenn er diesen Code liest. Durch die Verwendung
free()
entfernen Sie die Notwendigkeit, das Problem überhaupt zu berücksichtigen.Schließlich schreibt die Programmierung ein mentales Modell eines Prozesses in eine eindeutige Sprache, damit eine Person und ein Computer diesen Prozess perfekt verstehen können. Ein wesentlicher Bestandteil einer guten Programmierpraxis besteht darin, niemals unnötige Mehrdeutigkeiten einzuführen.
Intelligente Programmierung ist flexibel und allgemein. Schlechte Programmierung ist nicht eindeutig.
quelle
new
, sodass die meisten Speicherlecks sofort beseitigt werden. Nur wenn Sie unbedingt verwenden müssennew
. Das Ergebnisnew
muss sofort in einen intelligenten Zeiger eingefügt werden. Wenn Sie diese beiden Regeln befolgen, verlieren Sie einfach nie Speicher (außer bei einem Fehler in einer Bibliothek). Der einzige verbleibende Fall sindshared_ptr
Zyklen. In diesem Fall müssen Sie wissen, um sie zu verwendenweak_ptr
.Ich denke in Ihrer Situation könnte die Antwort sein, dass es in Ordnung ist. Sie müssen jedoch unbedingt dokumentieren, dass der Speicherverlust eine bewusste Entscheidung ist. Sie möchten nicht, dass ein Wartungsprogrammierer mitkommt, Ihren Code in eine Funktion einfügt und ihn millionenfach aufruft. Wenn Sie also die Entscheidung treffen, dass ein Leck in Ordnung ist, müssen Sie es (IN GROSSEN BRIEFEN) für jeden dokumentieren, der möglicherweise in Zukunft an dem Programm arbeiten muss.
Wenn dies eine Bibliothek eines Drittanbieters ist, sind Sie möglicherweise gefangen. Aber dokumentieren Sie auf jeden Fall, dass dieses Leck auftritt.
Aber im Grunde genommen ist es kein Problem, wenn der Speicherverlust eine bekannte Größe wie ein 512-KB-Puffer oder etwas anderes ist. Wenn der Speicherverlust wie bei jedem Aufruf eines Bibliotheksaufrufs weiter zunimmt, erhöht sich Ihr Speicher um 512 KB und wird nicht freigegeben, liegt möglicherweise ein Problem vor. Wenn Sie es dokumentieren und steuern, wie oft der Anruf ausgeführt wird, ist er möglicherweise verwaltbar. Aber dann brauchen Sie wirklich Dokumentation, denn während 512 nicht viel ist, sind 512 über eine Million Anrufe viel.
Außerdem müssen Sie die Dokumentation Ihres Betriebssystems überprüfen. Wenn dies ein eingebettetes Gerät war, gibt es möglicherweise Betriebssysteme, die nicht den gesamten Speicher von einem Programm freigeben, das beendet wird. Ich bin mir nicht sicher, vielleicht stimmt das nicht. Aber es lohnt sich, einen Blick darauf zu werfen.
quelle
Ich werde die unpopuläre, aber praktische Antwort geben, dass es immer falsch ist, Speicher freizugeben, es sei denn, dies verringert die Speichernutzung Ihres Programms . Zum Beispiel muss ein Programm, das eine einzelne Zuordnung oder eine Reihe von Zuordnungen zum Laden des Datensatzes vornimmt, den es während seiner gesamten Lebensdauer verwendet, nichts freigeben. Im häufigeren Fall eines großen Programms mit sehr dynamischen Speicheranforderungen (denken Sie an einen Webbrowser) sollten Sie natürlich so bald wie möglich Speicher freigeben, den Sie nicht mehr verwenden (z. B. Schließen eines Tabs / Dokuments / etc.) Es gibt jedoch keinen Grund, etwas freizugeben, wenn der Benutzer auf "Beenden" klickt. Dies ist für die Benutzererfahrung tatsächlich schädlich.
Warum? Zum Freigeben des Speichers muss der Speicher berührt werden. Selbst wenn die Malloc-Implementierung Ihres Systems keine Metadaten neben den zugewiesenen Speicherblöcken speichert, werden Sie wahrscheinlich rekursive Strukturen durchlaufen, um alle Zeiger zu finden, die Sie freigeben müssen.
Angenommen, Ihr Programm hat mit einem großen Datenvolumen gearbeitet, das meiste jedoch eine Weile nicht mehr berührt (auch hier ist der Webbrowser ein gutes Beispiel). Wenn der Benutzer viele Apps ausführt, wurde wahrscheinlich ein großer Teil dieser Daten auf die Festplatte übertragen. Wenn Sie nur (0) beenden oder von main zurückkehren, wird es sofort beendet. Tolle Benutzererfahrung. Wenn Sie sich die Mühe machen, alles freizugeben, können Sie 5 Sekunden oder länger damit verbringen, alle Daten wieder einzutauschen, um sie unmittelbar danach wegzuwerfen. Zeitverschwendung des Benutzers. Verschwendung der Akkulaufzeit des Laptops. Verschleißverschwendung auf der Festplatte.
Dies ist nicht nur theoretisch. Immer wenn zu viele Apps geladen sind und die Festplatte kaputt geht, denke ich nicht einmal daran, auf "Beenden" zu klicken. Ich komme so schnell ich kann zu einem Terminal und tippe killall -9 ... weil ich weiß, dass "exit" es nur noch schlimmer macht.
quelle
Ich bin sicher, dass jemand einen Grund finden kann, Ja zu sagen, aber ich werde es nicht sein. Anstatt nein zu sagen, werde ich sagen, dass dies keine Ja / Nein-Frage sein sollte. Es gibt Möglichkeiten, Speicherlecks zu verwalten oder einzudämmen, und viele Systeme haben sie.
Es gibt NASA-Systeme auf Geräten, die die Erde verlassen und dies planen. Die Systeme werden von Zeit zu Zeit automatisch neu gestartet, damit Speicherverluste für den Gesamtbetrieb nicht schwerwiegend werden. Nur ein Beispiel für Eindämmung.
quelle
Wenn Sie Speicher zuweisen und bis zur letzten Zeile Ihres Programms verwenden, ist dies kein Leck. Wenn Sie Speicher zuweisen und ihn vergessen, auch wenn der Speicher nicht wächst, ist dies ein Problem. Dieser zugewiesene, aber nicht verwendete Speicher kann dazu führen, dass andere Programme langsamer oder gar nicht ausgeführt werden.
quelle
Ich kann einerseits die Anzahl der "gutartigen" Lecks zählen, die ich im Laufe der Zeit gesehen habe.
Die Antwort ist also ein sehr qualifiziertes Ja.
Ein Beispiel. Wenn Sie eine Singleton-Ressource haben, die einen Puffer zum Speichern einer kreisförmigen Warteschlange oder eines Deque benötigt, aber nicht weiß, wie groß der Puffer sein muss, und sich den Aufwand für das Sperren oder jeden Leser nicht leisten können, dann weisen Sie aber einen exponentiell verdoppelten Puffer zu Wenn die alten nicht freigegeben werden, wird eine begrenzte Menge an Speicher pro Warteschlange / Deque verloren gehen. Der Vorteil für diese ist, dass sie jeden Zugriff dramatisch beschleunigen und die Asymptotik von Multiprozessor-Lösungen ändern können, indem sie niemals das Risiko einer Sperre eingehen.
Ich habe gesehen, dass dieser Ansatz von großem Nutzen für Dinge mit sehr klar festgelegten Zählwerten ist, wie z. B. Deques pro CPU, die Arbeit stehlen, und in viel geringerem Maße für den Puffer, der verwendet wird, um den Singleton-
/proc/self/maps
Status in Hans Böhms konservativem Garbage Collector für C zu halten / C ++, mit dem die Root-Sets usw. erkannt werden.Obwohl es sich technisch gesehen um ein Leck handelt, sind beide Fälle in ihrer Größe begrenzt, und im Fall der wachsenden kreisförmigen Arbeit, die Deque stiehlt, gibt es einen enormen Leistungsgewinn im Austausch gegen einen begrenzten Faktor von 2, der die Speichernutzung für die Warteschlangen erhöht.
quelle
Wenn Sie zu Beginn Ihres Programms eine Menge Heap zuweisen und diese beim Beenden nicht freigeben, ist dies per se kein Speicherverlust. Ein Speicherverlust liegt vor, wenn Ihr Programm einen Codeabschnitt durchläuft und dieser Code Heap zuweist und dann den Überblick verliert, ohne ihn freizugeben.
Es ist nicht erforderlich, direkt vor dem Beenden free () anzurufen oder zu löschen. Wenn der Prozess beendet wird, wird der gesamte Speicher vom Betriebssystem zurückgefordert (dies ist sicherlich bei POSIX der Fall. Bei anderen Betriebssystemen - insbesondere bei eingebetteten - YMMV).
Die einzige Vorsicht, die ich hätte, wenn ich den Speicher beim Beenden nicht freigeben würde, ist, dass wenn Sie Ihr Programm jemals so umgestalten, dass es beispielsweise zu einem Dienst wird, der auf Eingaben wartet, alles tut, was Ihr Programm tut, und dann herumläuft, um darauf zu warten ein anderer Service - Aufruf, dann , was Sie codieren haben kann wiederum in ein Speicherleck.
quelle
Dies ist so domänenspezifisch, dass es sich kaum lohnt, darauf zu antworten. benutze deinen verdammten Kopf.
und es gibt ein Spektrum von Zwischensituationen.
Die Opportunitätskosten ($$$) für die Verzögerung einer Produktfreigabe, um alle bis auf die schlimmsten Speicherlecks zu beheben, stellen normalerweise das Gefühl in den Schatten, "schlampig oder unprofessionell" zu sein. Ihr Chef bezahlt Sie dafür, dass Sie ihm Geld verdienen und keine warmen, verschwommenen Gefühle bekommen.
quelle
Sie müssen zuerst erkennen, dass es einen großen Unterschied zwischen einem wahrgenommenen Speicherverlust und einem tatsächlichen Speicherverlust gibt. Sehr häufig melden Analysetools viele rote Heringe und kennzeichnen etwas als durchgesickert (Speicher oder Ressourcen wie Handles usw.), wo es tatsächlich nicht vorhanden ist. Dies liegt häufig an der Architektur des Analysetools. Beispielsweise melden bestimmte Analysetools Laufzeitobjekte als Speicherlecks, da diese Objekte nie freigegeben werden. Die Freigabe erfolgt jedoch im Shutdown-Code der Laufzeit, den das Analysetool möglicherweise nicht sehen kann.
Trotzdem wird es immer noch Zeiten geben, in denen Sie tatsächlich Speicherlecks haben, die entweder sehr schwer zu finden oder sehr schwer zu beheben sind. Nun stellt sich die Frage, ob es jemals in Ordnung ist, sie im Code zu belassen.
Die ideale Antwort lautet: "Nein, niemals." Eine pragmatischere Antwort könnte "nein, fast nie" sein. Sehr oft haben Sie im wirklichen Leben nur eine begrenzte Anzahl von Ressourcen und Zeit zum Lösen und eine endlose Liste von Aufgaben. Wenn eine der Aufgaben darin besteht, Speicherlecks zu beseitigen, kommt sehr oft das Gesetz der Verringerung der Rendite zum Tragen. Sie könnten beispielsweise 98% aller Speicherlecks in einer Anwendung in einer Woche beseitigen, die restlichen 2% können jedoch Monate dauern. In einigen Fällen kann es aufgrund der Architektur der Anwendung sogar unmöglich sein, bestimmte Lecks zu beseitigen, ohne den Code grundlegend umzugestalten. Sie müssen die Kosten und den Nutzen der Eliminierung der verbleibenden 2% abwägen.
quelle
In dieser Art von Frage ist der Kontext alles. Persönlich kann ich Lecks nicht ausstehen, und in meinem Code bemühe ich mich sehr, sie zu beheben, wenn sie auftauchen, aber es lohnt sich nicht immer, ein Leck zu beheben, und wenn mich die Leute gelegentlich stundenweise bezahlen sagte ihnen, es sei meine Gebühr nicht wert, ein Leck in ihrem Code zu beheben. Lassen Sie mich Ihnen ein Beispiel geben:
Ich habe ein Projekt ausprobiert, einige Perf-Arbeiten durchgeführt und viele Fehler behoben. Während der Anwendungsinitialisierung gab es ein Leck, das ich aufgespürt und vollständig verstanden habe. Um es richtig zu reparieren, hätte es ungefähr einen Tag gedauert, einen Teil des ansonsten funktionalen Codes zu überarbeiten. Ich hätte etwas Hackiges tun können (wie den Wert in ein globales zu stopfen und ihn irgendwann zu greifen, von dem ich weiß, dass er nicht mehr zum Freigeben verwendet wird), aber das hätte dem nächsten Mann, der den Code berühren musste, nur mehr Verwirrung gebracht.
Persönlich hätte ich den Code überhaupt nicht so geschrieben, aber die meisten von uns können nicht immer an makellosen, gut gestalteten Codebasen arbeiten, und manchmal muss man diese Dinge pragmatisch betrachten. Die Zeit, die ich gebraucht hätte, um dieses 150-Byte-Leck zu beheben, könnte stattdessen für algorithmische Verbesserungen aufgewendet werden, die Megabyte RAM sparen.
Letztendlich entschied ich, dass es sich nicht lohnt, 150 Bytes für eine App zu verlieren, die rund einen Gig RAM verwendet und auf einem dedizierten Computer ausgeführt wird. Deshalb schrieb ich einen Kommentar, dass sie durchgesickert ist und geändert werden muss, um das Problem zu beheben es, und warum es es zu der Zeit nicht wert war.
quelle
Während sich die meisten Antworten auf echte Speicherlecks konzentrieren (die niemals in Ordnung sind, weil sie ein Zeichen für schlampige Codierung sind), erscheint mir dieser Teil der Frage interessanter:
Wenn der zugehörige Speicher verwendet wird, können Sie ihn nicht freigeben, bevor das Programm endet. Ob die Freigabe durch den Programmexit oder durch das Betriebssystem erfolgt, spielt keine Rolle. Solange dies dokumentiert ist, damit Änderungen keine echten Speicherlecks verursachen und solange kein C ++ - Destruktor oder keine C-Bereinigungsfunktion im Bild enthalten ist. Eine nicht geschlossene Datei wird möglicherweise durch ein durchgesickertes
FILE
Objekt angezeigt, aber ein fehlendes fclose () kann auch dazu führen, dass der Puffer nicht geleert wird.Zurück zum ursprünglichen Fall ist es meiner Meinung nach an sich vollkommen in Ordnung, so sehr, dass Valgrind, einer der leistungsstärksten Lecksucher, solche Lecks nur auf Anfrage behandelt. Wenn Sie in Valgrind einen Zeiger überschreiben, ohne ihn zuvor freizugeben, wird dies als Speicherverlust angesehen, da es wahrscheinlicher ist, dass er erneut auftritt und der Heap endlos wächst.
Dann gibt es keine freigegebenen Speicherblöcke, die noch erreichbar sind. Man könnte sicherstellen, dass alle am Ausgang befreit werden, aber das ist nur Zeitverschwendung an sich. Der Punkt ist , wenn sie befreit werden kann , bevor . Das Verringern des Speicherverbrauchs ist in jedem Fall nützlich.
quelle
Ich stimme vfilby zu - es kommt darauf an. In Windows behandeln wir Speicherlecks als relativ schwerwiegende Fehler. Aber es hängt sehr stark von der Komponente ab.
Beispielsweise sind Speicherlecks für Komponenten, die selten und für begrenzte Zeiträume ausgeführt werden, nicht sehr schwerwiegend. Diese Komponenten werden ausgeführt, erledigen ihre Arbeit und werden dann beendet. Wenn sie den gesamten Speicher verlassen, wird implizit ihr Speicher freigegeben.
Speicherverluste in Diensten oder anderen langfristigen Komponenten (wie der Shell) sind jedoch sehr schwerwiegend. Der Grund ist, dass diese Fehler im Laufe der Zeit Speicher stehlen. Die einzige Möglichkeit, dies wiederherzustellen, besteht darin, die Komponenten neu zu starten. Die meisten Benutzer wissen nicht, wie sie einen Dienst oder die Shell neu starten sollen. Wenn also ihre Systemleistung leidet, starten sie einfach neu.
Wenn Sie also ein Leck haben, bewerten Sie die Auswirkungen auf zwei Arten
Vordecker
quelle
Selbst wenn Sie sicher sind, dass Ihr "bekannter" Speicherverlust kein Chaos verursacht, tun Sie es nicht. Bestenfalls wird es Ihnen den Weg ebnen, einen ähnlichen und wahrscheinlich kritischeren Fehler zu einem anderen Zeitpunkt und an einem anderen Ort zu machen.
Das zu fragen ist für mich wie zu fragen: "Kann ich um 3 Uhr morgens das rote Licht brechen, wenn niemand in der Nähe ist?". Sicher, es kann zu diesem Zeitpunkt keine Probleme verursachen, aber es bietet Ihnen einen Hebel, um dasselbe in der Hauptverkehrszeit zu tun!
quelle
Nein, Sie sollten keine Lecks haben, die das Betriebssystem für Sie bereinigt. Der Grund (in den obigen Antworten nicht erwähnt, soweit ich das überprüfen konnte) ist, dass Sie nie wissen, wann Ihr main () als Funktion / Modul in einem anderen Programm wiederverwendet wird . Wenn Ihr main () eine häufig aufgerufene Funktion in der Software einer anderen Person ist, weist diese Software einen Speicherverlust auf, der mit der Zeit Speicher verbraucht.
KIV
quelle
Ich denke, es ist in Ordnung, wenn Sie ein Programm schreiben, das Speicherverluste verursachen soll (dh um die Auswirkungen von Speicherverlusten auf die Systemleistung zu testen).
quelle
Ich bin überrascht, so viele falsche Definitionen zu sehen, was ein Speicherverlust tatsächlich ist. Ohne eine konkrete Definition wird eine Diskussion darüber, ob es eine schlechte Sache ist oder nicht, nirgendwo hin führen.
Wie einige Kommentatoren zu Recht hervorgehoben haben, tritt ein Speicherverlust nur dann auf, wenn der von einem Prozess zugewiesene Speicher außerhalb des Bereichs liegt, sofern der Prozess nicht mehr in der Lage ist, ihn zu referenzieren oder zu löschen.
Ein Prozess, der immer mehr Speicherplatz beansprucht, ist nicht unbedingt undicht. Solange es in der Lage ist, diesen Speicher zu referenzieren und freizugeben, bleibt es unter der expliziten Kontrolle des Prozesses und ist nicht durchgesickert. Der Prozess ist möglicherweise schlecht konzipiert, insbesondere im Kontext eines Systems, in dem der Speicher begrenzt ist, dies ist jedoch nicht dasselbe wie ein Leck. Umgekehrt ist der Verlust des Umfangs von beispielsweise einem 32-Byte-Puffer immer noch ein Leck, obwohl die Menge des durchgesickerten Speichers gering ist. Wenn Sie der Meinung sind, dass dies unbedeutend ist, warten Sie, bis jemand einen Algorithmus um Ihren Bibliotheksaufruf wickelt und ihn 10.000 Mal aufruft.
Ich sehe überhaupt keinen Grund, Lecks in Ihrem eigenen Code zuzulassen, wie klein sie auch sein mögen. Moderne Programmiersprachen wie C und C ++ sind sehr bemüht, Programmierern dabei zu helfen, solche Lecks zu vermeiden, und es gibt selten ein gutes Argument, keine guten Programmiertechniken anzuwenden - insbesondere in Verbindung mit bestimmten Sprachfunktionen -, um Lecks zu verhindern.
In Bezug auf vorhandenen Code oder Code von Drittanbietern, bei dem Ihre Kontrolle über die Qualität oder die Fähigkeit, Änderungen vorzunehmen, je nach Schwere des Lecks stark eingeschränkt sein kann, müssen Sie möglicherweise Maßnahmen ergreifen oder abschwächen, z. B. einen regelmäßigen Neustart Ihres Prozesses, um diese zu reduzieren die Wirkung des Lecks.
Es ist möglicherweise nicht möglich, den vorhandenen (undichten) Code zu ändern oder zu ersetzen. Daher müssen Sie ihn möglicherweise akzeptieren. Dies ist jedoch nicht gleichbedeutend mit der Erklärung, dass es in Ordnung ist.
quelle
Es ist wirklich kein Leck, wenn es beabsichtigt ist, und es ist kein Problem, es sei denn, es ist eine signifikante Menge an Speicher oder könnte zu einer signifikanten Menge an Speicher werden. Es ist ziemlich üblich, globale Zuordnungen während der Laufzeit eines Programms nicht zu bereinigen. Wenn sich das Leck in einem Server oder einer lang laufenden App befindet und mit der Zeit wächst, ist dies ein Problem.
quelle
Ich denke, Sie haben Ihre eigene Frage beantwortet. Der größte Nachteil ist, wie sie die Tools zur Erkennung von Speicherlecks stören, aber ich denke, dass der Nachteil für bestimmte Arten von Anwendungen ein RIESIGER Nachteil ist.
Ich arbeite mit Legacy-Serveranwendungen, die solide sein sollen, aber Lecks aufweisen und die globalen Funktionen den Speichererkennungstools im Wege stehen. Es ist ein großes Geschäft.
In dem Buch "Collapse" von Jared Diamond fragt sich der Autor, was der Typ gedacht hat, der den letzten Baum auf der Osterinsel gefällt hat, den Baum, den er gebraucht hätte, um ein Kanu zu bauen, um die Insel zu verlassen. Ich frage mich an den Tag vor vielen Jahren, als dieser erste Globus zu unserer Codebasis hinzugefügt wurde. Das war der Tag, an dem es hätte gefangen werden sollen.
quelle
Ich sehe das gleiche Problem wie bei allen Szenario-Fragen wie folgt: Was passiert, wenn sich das Programm ändert und plötzlich dieser kleine Speicherverlust zehn Millionen Mal aufgerufen wird und sich das Ende Ihres Programms an einem anderen Ort befindet, sodass es wichtig ist? Wenn es sich in einer Bibliothek befindet, protokollieren Sie einen Fehler bei den Bibliotheksverwaltern. Fügen Sie kein Leck in Ihren eigenen Code ein.
quelle
Ich werde nein antworten.
Theoretisch wird das Betriebssystem nach Ihnen aufgeräumt, wenn Sie ein Durcheinander hinterlassen (das ist jetzt nur unhöflich, aber da Computer keine Gefühle haben, ist dies möglicherweise akzeptabel). Sie können jedoch nicht jede mögliche Situation vorhersehen, die beim Ausführen Ihres Programms auftreten kann. Daher ist das Erstellen von Speicherlecks (es sei denn, Sie können einen formalen Beweis für ein bestimmtes Verhalten erbringen) aus professioneller Sicht einfach unverantwortlich und schlampig.
Wenn eine Komponente eines Drittanbieters Speicher verliert, ist dies ein sehr starkes Argument gegen die Verwendung, nicht nur wegen des bevorstehenden Effekts, sondern auch, weil es zeigt, dass die Programmierer schlampig arbeiten und dies auch andere Metriken beeinflussen kann. Wenn man Legacy-Systeme betrachtet, ist dies schwierig (betrachten Sie Webbrowsing-Komponenten: Meines Wissens verlieren alle Speicherplatz), aber es sollte die Norm sein.
quelle
In der Vergangenheit war dies bei einigen Betriebssystemen unter bestimmten Randbedingungen von Bedeutung. Diese Randfälle könnten in Zukunft existieren.
Hier ist ein Beispiel: Unter SunOS in der Sun 3-Ära gab es ein Problem, wenn ein Prozess exec (oder traditionell Fork und dann Exec) verwendete, der nachfolgende neue Prozess denselben Speicherbedarf erbte wie der übergeordnete Prozess und nicht verkleinert werden konnte . Wenn ein übergeordneter Prozess 1/2 Gig Speicher zugewiesen und ihn vor dem Aufruf von exec nicht freigegeben hat, verwendet der untergeordnete Prozess denselben 1/2 Gig (obwohl er nicht zugewiesen wurde). Dieses Verhalten wurde am besten von SunTools (ihrem Standard-Fenstersystem) gezeigt, das ein Speicherfresser war. Jede App, die sie hervorgebracht hat, wurde über Fork / Exec erstellt und hat den SunTools-Footprint geerbt, wodurch der Swap-Bereich schnell gefüllt wurde.
quelle
Dies wurde bereits ad nauseam diskutiert . Fazit ist, dass ein Speicherverlust ein Fehler ist und behoben werden muss. Wenn eine Bibliothek eines Drittanbieters Speicher verliert, fragt man sich, was sonst noch daran falsch ist, nein? Wenn Sie ein Auto bauen würden, würden Sie einen Motor verwenden, aus dem gelegentlich Öl austritt? Immerhin hat jemand anderes den Motor gebaut, also ist es nicht deine Schuld und du kannst ihn nicht reparieren, oder?
quelle
Im Allgemeinen ist ein Speicherverlust in einer eigenständigen Anwendung nicht schwerwiegend, da er beim Beenden des Programms bereinigt wird.
Was tun Sie für Serverprogramme, die so konzipiert sind, dass sie nicht beendet werden?
Wenn Sie ein Programmierer sind, der keinen Code entwirft und implementiert, bei dem die Ressourcen korrekt zugewiesen und freigegeben werden, möchte ich nichts mit Ihnen oder Ihrem Code zu tun haben. Was ist mit Ihren Sperren, wenn Sie Ihren durchgesickerten Speicher nicht bereinigen möchten? Lässt du sie auch da draußen hängen? Hinterlassen Sie kleine Mengen temporärer Dateien in verschiedenen Verzeichnissen?
Den Speicher verlieren und das Programm ihn bereinigen lassen? Nein auf keinen Fall. Es ist eine schlechte Angewohnheit, die zu Fehlern, Fehlern und mehr Fehlern führt.
Räumen Sie nach sich selbst auf. Yo Mama arbeitet hier nicht mehr.
quelle
Wenn Sie Speicherlecks haben, die Sie nicht vermeiden können, müssen Sie in der Regel genauer über den Besitz von Objekten nachdenken.
Aber auf Ihre Frage lautet meine Antwort auf den Punkt gebracht: Im Produktionscode, ja. Während der Entwicklung nein . Dies mag rückwärts erscheinen, aber hier ist meine Argumentation:
In der von Ihnen beschriebenen Situation, in der der Speicher bis zum Ende des Programms gespeichert bleibt, ist es vollkommen in Ordnung, ihn nicht freizugeben. Sobald Ihr Prozess beendet ist, wird das Betriebssystem trotzdem bereinigt. Tatsächlich könnte dies die Benutzererfahrung verbessern: In einem Spiel, an dem ich gearbeitet habe, dachten die Programmierer, es wäre sauberer, den gesamten Speicher vor dem Beenden freizugeben, was das Herunterfahren des Programms bis zu einer halben Minute dauern würde! Eine schnelle Änderung, die nur exit () genannt wurde, ließ den Prozess sofort verschwinden und brachte den Benutzer zurück auf den Desktop, auf dem er sein wollte.
Sie haben jedoch Recht mit den Debugging-Tools: Sie lösen einen Anfall aus, und all die Fehlalarme können dazu führen, dass das Auffinden Ihrer echten Speicherlecks schmerzhaft wird. Schreiben Sie deshalb immer Debugging-Code, der den Speicher freigibt, und deaktivieren Sie ihn beim Versand.
quelle