Sind Speicherlecks jemals in Ordnung? [geschlossen]

231

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.

durchdringen
quelle
50
Wenn der Speicherverbrauch mit der Zeit nicht wächst, ist dies kein Leck.
mpez0
4
Die meisten Anwendungen (einschließlich aller .NET-Programme) verfügen über mindestens einige Puffer, die einmal zugewiesen und nie explizit freigegeben wurden. Daher ist die Definition von mpez0 nützlicher.
Ben Voigt
2
Ja, wenn Sie unendlich viel Gedächtnis haben.
Benutzer
Ein "gutartiges" Leck (wenn es so etwas gibt) ist kein falsches Positiv - es ist ein Leck, das sehr korrekt erkannt wurde. Die Lecksuche ist selbst bei Lecks, die Sie persönlich nicht beheben möchten, der Hauptgrund für die Existenz eines Lecksuchers.
CHao
1
@ mpez0 "Wenn der Speicherverbrauch mit der Zeit nicht wächst, ist es kein Leck"? Das ist nicht die Definition eines Speicherverlusts. Ein Leck ist ein Speicher, der durchgesickert ist, was bedeutet, dass er nicht freigegeben wurde und Sie keinen Hinweis mehr darauf haben. Daher ist es für Sie unmöglich, ihn jemals wieder freizugeben. Ob es wächst oder nicht, ist irrelevant.
Mecki

Antworten:

329

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.

JohnMcG
quelle
57
Richtig und nicht wahr zugleich. Letztendlich sind die meisten von uns Lohnsklaven, und jeder Wunsch nach Handwerkskunst muss den Anforderungen des Unternehmens in den Hintergrund treten. Wenn diese Bibliothek eines Drittanbieters ein Leck aufweist und 2 Wochen Arbeit spart, kann es einen Geschäftsfall geben, um sie zu verwenden, usw.
Cervo
3
Ich würde die Bibliothek trotzdem benutzen, wenn es etwas war, das ich brauchte und es keine anständigen Alternativen gab, aber ich würde einen Fehler bei den Betreuern protokollieren.
Tloach
7
Während ich persönlich genau die gleiche Antwort geben würde, gibt es Programme, die kaum Speicherplatz freigeben. Der Grund dafür ist, dass sie a) auf Betriebssystemen mit freiem Speicher ausgeführt werden sollen und b) nicht sehr lange ausgeführt werden sollen. Seltene Einschränkungen für ein Programm, aber ich akzeptiere dies als vollkommen gültig.
2
Um einige Gründe für eine frühzeitige Überprüfung hinzuzufügen: Wenn Ihre Debugging-Tools mit "harmlosen" Lecks überflutet sind, wie werden Sie die "echte" finden? Wenn Sie eine Batch-Funktion hinzufügen und Ihr 1K / Stunde-Leck plötzlich 1K / Sekunde beträgt?
Peterchen
5
Hmm ist "kein Speicherleck" "perfekt"?
JohnMcG
80

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.

Jim C.
quelle
12
Technisch gesehen ist ein Leck ein Speicher, der zugewiesen wird und alle Verweise darauf gehen verloren. Es ist einfach faul, den Speicher am Ende nicht freizugeben.
Martin York
17
Wenn Sie einen einmaligen Speicherverlust von 4 GB haben, ist dies ein Problem.
John Dibling
21
Egal ob es wächst oder nicht. Andere Programme können den Speicher nicht verwenden, wenn Sie ihn zugewiesen haben.
Bill the Lizard
8
> Andere Programme können den Speicher nicht verwenden, wenn Sie ihn zugewiesen haben. Nun, das Betriebssystem kann Ihren Speicher jederzeit auf die Festplatte austauschen und anderen Anwendungen ermöglichen, den RAM zu verwenden, den Sie nicht genutzt haben.
Max Lybbert
4
Wenn das Programm sehr kurzlebig ist, ist ein Leck möglicherweise nicht so schlimm. Auch wenn Paging NICHT ideal ist, ist es nicht so teuer, wie manche hier glauben, weil das Programm nicht an diesem Speicher interessiert ist (und daher nicht die ganze Zeit ausgetauscht wird) - es sei denn, Sie haben natürlich einen GC ...
Arafangion
79

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:

#define BLK ((size_t)1024)
while(1){
    void * vp = malloc(BLK);
}

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

int main(){
    void * vp = malloc(LOTS);
    // Go do something useful
    return 0;
}

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.

Charlie Martin
quelle
Betrachten Sie nun ein paar Dutzend dieser Zuweisungen. Überlegen Sie nun, ob Sie den "Hauptkörper" in eine Routine verschieben müssen, die mehrmals aufgerufen wird. Genießen. - Ich stimme dem Gefühl zu, dass es in diesem Szenario kein so großes Problem ist, aber die Szenarien ändern sich. Wie sie sagen, schreiben Sie immer Code, als ob der Typ, der ihn wartet, weiß, wo Sie leben.
Peterchen
2
Nun, der Punkt ist, dass der Speicher, der gespeichert und gehalten wird, bis das Programm _exit () aufruft, nicht "durchgesickert" ist.
Charlie Martin
1
Es ist ein Speicherverlust und kann Ihr Programm beeinträchtigen. Zukünftige Zuweisungen können aufgrund dieses Prozesses fehlschlagen, da Sie sicher überprüfen, dass malloc überall nicht null zurückgegeben hat. Durch übermäßige Nutzung des Gedächtnisses, beispielsweise in einer eingebetteten Situation, in der das Gedächtnis knapp ist, kann dies den Unterschied zwischen Leben und Tod ausmachen.
MikeJ
10
Mike, das stimmt einfach nicht. In einer kompatiblen C-Umgebung werden durch das Beenden von main alle Prozessressourcen freigegeben. In einer eingebetteten Umgebung, wie Sie sie beschreiben, sehen Sie diese Situation möglicherweise, aber Sie hätten keine Hauptumgebung. Jetzt gebe ich zu, dass es möglicherweise fehlerhafte eingebettete Umgebungen gibt, für die dies nicht zutrifft, aber dann habe ich fehlerhafte Umgebungen gesehen, die + = auch nicht richtig verarbeiten konnten.
Charlie Martin
3
Ja, Sie haben jetzt festgestellt, dass malloces eine schlechte Sache ist , wenn Sie zu viel Speicher haben. Es ist immer noch kein Leck . Es ist kein Leck, bis es ein mallocSpeicher ist, auf den die Referenz verloren geht.
Charlie Martin
39

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?

vfilby
quelle
Ich weiß nicht, ob Sie meine ganze Frage gelesen haben oder nicht. Ich sage, dass der Speicher bis zum Ende der Anwendung verwendet wird. Es wächst nicht mit der Zeit. Das einzige Nein Nein ist, dass es keinen Aufruf zum Freigeben / Löschen gibt.
Imbue
2
Dann ist es nicht wirklich ein Speicherverlust. Ein Speicherverlust besteht aus kleinen Mengen nicht verwendeten, aber nicht freigegebenen Speichers. Diese Menge wird mit der Zeit größer. Sie sprechen von einem Speichertröpfchen. Kümmere dich nicht darum, es sei denn, dein Tröpfchen ist sehr groß.
Vfilby
"Wenn es kein Problem verursacht, ist es dann wirklich wichtig?" Nein, das spielt überhaupt keine Rolle. Ich wünschte, mehr Menschen hätten das, anstatt religiös zu werden.
Imbue
2
@ John: Das ist im Allgemeinen weniger eine Frage fauler Entwickler als vielmehr eine Frage der Weiterentwicklung von Software. Wir alle machen Fehler, Fehler sind unser Beruf; wir machen sie wir reparieren sie, das ist was wir tun. Es ist immer ein Gleichgewicht zwischen Vorabkosten und langfristiger Wartung, dieses Gleichgewicht ist niemals einfach.
Vfilby
1
John, ich stimme dir zu 100% zu. Imbum Die Frage ist fast: "Wie viel akzeptierst du?". Schlampig ist schlampig. Wie wäre es, wenn ich eine Garnele hinter Ihrem Monitor zurücklasse. Gestank ist Gestank. Jedes Mal, wenn wir nachgeben, gibt unsere Industrie ein bisschen nach. Wenn Sie wissen, dass ein Leck vorliegt und Sie wissen, dass Sie es verursacht haben, sollten Sie es beheben.
Baash05
37

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. mallocund andere Arten der Speicherverwaltung rufen Seiten vom Betriebssystem ab und verwalten sie nach Belieben. Es ist ziemlich wahrscheinlich , dass free()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.

Artelius
quelle
1
Was ist, wenn andere Programme den Speicher benötigen, den Ihr Programm unnötig hält, und obwohl Sie möglicherweise keine Mallocs mehr benötigen, geben Sie die nicht verwendeten Speicherplätze frei () :)
MN
2
Du hast meinen Standpunkt völlig verfehlt. Wenn Sie Speicher freigeben (), können andere Programme ihn nicht verwenden !! (Manchmal können sie es, besonders wenn Sie große Speicherblöcke freigeben. Aber oft können sie nicht!) Ich werde meinen Beitrag bearbeiten, um dies klarer zu machen.
Artelius
27

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.

kasperjj
quelle
Informationen zu Skriptsprachen: Python verwendet Refcounting, verfügt jedoch über einen GC, um zyklische Referenzen freizugeben. In anderen Sprachen vermeidet der Programmierer häufig explizit zyklische Verweise insgesamt, was zu anderen Problemen führt.
Blaisorblade
Die früheren Versionen von PHP haben keinen Speicher freigegeben, sondern nur von Anfang bis Ende im Speicher gewachsen. Nach der typischen Ausführungszeit von 0,1 Sekunden wurde das Skript beendet und der gesamte Speicher zurückgefordert.
Arafangion
19

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ühren free()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()und free()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.

Jason L.
quelle
Ich liebe die Gewohnheitsidee. Ich stimme auch zu. Wenn ich ein Speicherleck sehe, frage ich mich immer, welche andere Ecke der Codierer geschnitten hat. Besonders wenn es offensichtlich ist
baash05
Dies ist bei weitem die beste Antwort. Ich programmiere jetzt seit 5 Jahren in C ++ und habe noch nie einen einzigen Speicherverlust geschrieben. Der Grund ist, dass ich keinen Code schreibe, der dazu neigt, Speicher zu verlieren. Gutes C ++ - Design wird selten verwendet new, sodass die meisten Speicherlecks sofort beseitigt werden. Nur wenn Sie unbedingt verwenden müssen new. Das Ergebnis newmuss 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 sind shared_ptrZyklen. In diesem Fall müssen Sie wissen, um sie zu verwenden weak_ptr.
David Stone
15

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.

Cervo
quelle
3
"Aber Sie müssen definitiv dokumentieren, dass der Speicherverlust eine bewusste Entscheidung ist." Dem Himmel sei Dank. Der bisher beste Punkt.
Pestophagous
15

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.

R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
quelle
5
Ich liebe dieses Zitat von Raymond Chen: "Das Gebäude wird abgerissen. Machen Sie sich nicht die Mühe, den Boden zu fegen und die Mülleimer zu leeren und die Whiteboards zu löschen. Und stellen Sie sich nicht am Ausgang des Gebäudes auf, damit jeder seine Wohnung bewegen kann. Alles, was Sie tun, ist, das Abbruch-Team darauf warten zu lassen, dass Sie diese sinnlosen Hausputzaufgaben erledigen. " ( blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683 )
Andreas Magnusson
11

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.

pearcewg
quelle
Das ist eigentlich ein Beispiel für Software-Alterung. Faszinierendes Studienfach.
Konrad Rudolph
Hin und wieder ein automatischer Neustart, oder? NASA, was? (* schaut auf alte Microsoft Windows-Installations-CDs *) Dies erklärt so viel ...
Christian Severin
8

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.

Bill die Eidechse
quelle
Nicht wirklich, denn wenn es nicht verwendet wird, wird es nur ausgelagert. Wenn die App beendet wird, wird der gesamte Speicher freigegeben.
Eclipse
Solange es zugewiesen ist, können andere Programme es nicht verwenden. Es wird nicht ausgelagert, wenn Sie es nicht freigeben.
Bill the Lizard
Natürlich wird es das - darum geht es beim virtuellen Speicher. Sie können über 1 GB tatsächlichen Arbeitsspeicher verfügen und dennoch über 4 Prozesse verfügen, die jeweils 2 GB virtuellen Speicher vollständig zuweisen (sofern Ihre Auslagerungsdatei groß genug ist).
Eclipse
Natürlich treten böse Paging-Probleme auf, wenn jeder dieser Prozesse den gesamten Speicher aktiv nutzt.
Eclipse
Okay, ich verstehe, wovon du jetzt sprichst. Wenn Sie nicht freigegebenen Speicher freigeben, wird der Paging-Bedarf verringert. Wenn Sie es zugewiesen lassen, behält Ihre Anwendung es weiterhin, wenn es wieder eingelegt wird.
Bill the Lizard
8

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/mapsStatus 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.

Edward KMETT
quelle
1
Sie können Gefahrenhinweise verwenden, um das Leck zu verhindern.
Demi
8

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.

nsayer
quelle
Ich bin anderer Ansicht. Das ist "ein Speicherverlust an sich".
Konrad Rudolph
Es ist kein Leck, bis Sie den Verweis auf das Objekt "verlieren". Wenn der Speicher für die Lebensdauer des Programms verwendet wird, ist er vermutlich nicht durchgesickert. Wenn die Referenz nicht verloren geht, bis exit () aufgerufen wird, handelt es sich absolut nicht um ein Leck.
nsayer
Amiga DOS war der letzte O / SI-Blick, der hinter Prozessen nicht aufgeräumt wurde. Beachten Sie jedoch, dass der gemeinsam genutzte System V IPC-Speicher auch dann verbleiben kann, wenn kein Prozess ihn verwendet.
Jonathan Leffler
Palm gibt erst dann Speicher frei, wenn Sie hotsync. es kam gut nach dem Amiga. Ich habe Apps auf meinem Palm-Emulator ausgeführt, bei denen Lecks aufgetreten sind. Sie haben nie den Weg zu meiner eigentlichen Handfläche gefunden.
Baash05
6

Dies ist so domänenspezifisch, dass es sich kaum lohnt, darauf zu antworten. benutze deinen verdammten Kopf.

  • Space-Shuttle-Betriebssystem: Nein, keine Speicherlecks erlaubt
  • Schnelle Entwicklung Proof-of-Concept-Code: Das Beheben all dieser Speicherlecks ist Zeitverschwendung.

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.

Dustin Getz
quelle
2
Sehr kurzsichtige Haltung. Sie sagen im Grunde, dass es nicht notwendig ist, grundlegend solide Programmierpraktiken anzuwenden, bis festgestellt wird, dass ein Fehler durch diese Praktiken verursacht wird. Das Problem ist, dass Software, die mit schlampigen Methoden geschrieben wurde, tendenziell mehr Fehler aufweist als Software, die dies nicht ist.
John Dibling
1
Ich glaube das nicht alles. Und die Speicherverwaltung ist komplizierter als das Schreiben sauberer Methoden.
Dustin Getz
1
Dustin arbeitet offensichtlich in der realen Welt wie die meisten von uns, wo wir ständig gegen verrückte Fristen arbeiten, um mit der Konkurrenz Schritt zu halten. Der Umgang mit Fehlern sollte daher pragmatisch erfolgen. Wenn Sie zu viel Zeit mit unwichtigen Fehlern in unwichtigen Programmen verschwenden, werden Sie Ihre Aufgaben nicht erledigen.
Wouter van Nifterick
Das Problem mit dieser Einstellung ist: Wann beginnen Sie, die Lecks zu beheben? "OK, es ist ein Kraftwerk, aber es ist nur Kohle, nicht Uran. Warum hier Leckagen beheben?" - Ich habe in der realen Welt gelernt, dass es einfach nie passiert, wenn man nicht von Anfang an das Richtige tut. Diese Einstellung führt zu Projekten, die nach zwei Wochen zu 99% abgeschlossen sind und dies zwei Monate lang bleiben.
Peterchen
5

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.

John Dibling
quelle
5

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.

Louis Gerbarg
quelle
Clever. Zumal das Leck während der Initialisierung auftrat, was bedeutet, dass es sich nicht über die Laufzeit der Anwendung ansammelt.
Demi
5

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:

Was ist, wenn Sie Speicher zuweisen und ihn bis zur letzten Codezeile in Ihrer Anwendung verwenden (z. B. den Dekonstruktor 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?

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 FILEObjekt 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.

Blaisorblade
quelle
Wow ... jemand, der weiß, was ein Speicherverlust ist.
Simon Buchan
4

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

  1. Zu Ihrer Software und der Benutzererfahrung.
  2. Für das System (und den Benutzer) in Bezug auf den sparsamen Umgang mit Systemressourcen.
  3. Auswirkungen des Fixes auf Wartung und Zuverlässigkeit.
  4. Wahrscheinlichkeit, woanders eine Regression zu verursachen.

Vordecker

Foredecker
quelle
3. Auswirkungen auf die Wartung der Software.
Peterchen
3

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!

Bei ihrer
quelle
3

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
3

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).

Piep Piep
quelle
3

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.

Komponente 10
quelle
2

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.

Sanjaya R.
quelle
2

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.

Corey Trager
quelle
2

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.

tloach
quelle
In diesem Fall ändert sich die Auswirkung des Speicherverlusts, und Sie müssen die Priorität des Verstopfens des Lecks neu bewerten.
John Dibling
@ John: Dann dokumentieren Sie besser zumindest das Leck. Selbst dann würde ich niemandem vertrauen, der einen großen rot blinkenden Kommentar nicht ignoriert und undichten Code ohnehin kopiert und einfügt. Ich ziehe es vor, jemandem überhaupt nicht die Möglichkeit zu geben, dies zu tun.
Tloach
2

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.

Konrad Rudolph
quelle
2

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.

Sockel
quelle
2

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?

Dima
quelle
Aber wenn Sie ein Auto mit einem Motor besaßen, aus dem gelegentlich Öl austritt, geben Sie Geld aus, um es zu reparieren, oder behalten Sie den Ölstand im Auge und füllen Sie ihn von Zeit zu Zeit nach. Die Antwort hängt von allen möglichen Faktoren ab.
schlank
Hier geht es nicht darum, ein Auto zu besitzen. Hier geht es darum, ein Auto zu bauen. Wenn Sie eine Drittanbieter-Bibliothek mit Speicherlecks erhalten und diese unbedingt verwenden müssen, leben Sie damit. Wenn Sie jedoch ein System oder eine Bibliothek schreiben, liegt es in Ihrer Verantwortung, sicherzustellen, dass es fehlerfrei ist.
Dima
+1 behandle es wie jeden anderen Fehler. (Das bedeutet in meinem Buch nicht "sofort beheben", sondern "muss unbedingt fixiert werden")
Peterchen
2

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.

EvilTeach
quelle
Ich habe an Serverprogrammen gearbeitet, die absichtlich Prozesse anstelle von Threads verwenden, sodass Speicherlecks und Segmentierungsfehler nur begrenzten Schaden verursachen.
schlank
Interessanter Ansatz. Ich wäre ein bisschen besorgt über Prozesse, die nicht beendet werden können und weiterhin Speicher verschlingen.
EvilTeach
2

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.

Enno
quelle