Hallo,
Viele gängige Programmiersprachen (z.B. C#) kümmern sich um eine
automatische Speicherverwaltung per garbage Collector. Ich finde das
Konzept super, und auch in der Praxis sehr angenehm.
Trotzdem lese ich hier oft, dass bestimmte Zeitgenossen diese
Funktionalität verteufeln. Warum eigentlich? Was spricht gegen die
Verwendung einer automatischen Speicherverwaltung?
Hobbyist schrieb:> Trotzdem lese ich hier oft, dass bestimmte Zeitgenossen diese> Funktionalität verteufeln. Warum eigentlich? Was spricht gegen die> Verwendung einer automatischen Speicherverwaltung?
Der Anwendungsbereich.
Auf einem Mikrocontroller wuerde sich der Overhead eines GC sehr
bemerkbar machen.
Das und Generationskonflikte.. ;)
Die alte Laier von "Derjenige der weiss was er macht, braucht das nicht"
Hobbyist schrieb:> Trotzdem lese ich hier oft, dass bestimmte Zeitgenossen diese> Funktionalität verteufeln. Warum eigentlich? Was spricht gegen die> Verwendung einer automatischen Speicherverwaltung?
Das Verhalten ist nicht vorhersehbar. Und das Letzte, was man bei
manchen Mikrocontroller-Anwendungen möchte, ist nicht vorhersehbares
Verhalten. Stell dir vor, bei deinem ABS-System im Auto verzögert sich
die Bremsensteuerung, weil der zuständige Mikrocontroller gerade damit
beschäftigt ist den Speicher aufzuräumen statt die notwendigen
Steuerbefehle zu geben.
Mladen G. schrieb:> Auf einem Mikrocontroller wuerde sich der Overhead eines GC sehr> bemerkbar machen.Mark 99 schrieb:> Und das Letzte, was man bei> manchen Mikrocontroller-Anwendungen möchte, ist nicht vorhersehbares> Verhalten
Achso, das bezog sich also ausschließlich auf µC-Anwendungen. Klar, da
verzichtet man besser auf sowas.
Ich hatte jetzt eher Desktop-Anwendungen im Kopf. Da sehe ich kein
Grund, auf eine automatische Speicherverwaltung zu verzichten.
Danke für die Hinweise!
Hobbyist schrieb:> Da sehe ich kein> Grund, auf eine automatische Speicherverwaltung zu verzichten.
ich schon, es funktioniert einfach nicht 100%.
Fast jede javaanwendung hat ein Speichleck. Je länger sie laufen, desto
mehr Speicher wird verwendet.
Bei einfachen Objekten mag das ja noch alles gehen, aber sobald
resourcen verwendet werden (files, Schriftarten, threads), klappt das
einfach nicht.
Dafür werden dann wie bei C# using verwendet.
Ich finde ein definiertes Verhalten wie bei c++ mit dem Destruktor
besser.
Peter II schrieb:> Fast jede javaanwendung hat ein Speichleck. Je länger sie laufen, desto> mehr Speicher wird verwendet.
Wenn ich mir das hier so ansehe
http://acadopus.de/java/die-typischen-faelle-von-memory-leaks-in-java-anwendungen_4002.html
dann hängen diese Probleme weniger mit GC zusammen, als mit der recht
freizügigen Verwendung von Speicher generell, mit Links an sonstundeiner
Stelle. Die meisten dort beschriebenen Effekte betreffen Speicher, der
tatsächlich noch referenziert wird, auch wenn die Links vielleicht
niemand mehr wirklich braucht. Ob das dann per GC oder anders behandelt
wird ändert nichts am Volumen.
Mark 99 schrieb:> Das Verhalten ist nicht vorhersehbar.
Ach, jetzt laßt doch endlich diese Ammenmärchen. Es gibt seit
Jahrzehnten speziell für den Embedded-Bereich entwickelte GCs, die nicht
nur berechenbar sind, sondern sogar Echtzeitgarantien geben.
Natürlich kann man nicht den für den PC entwickelten "Standard-"C#-GC
damit vergleichen.
Peter II schrieb:> ich schon, es funktioniert einfach nicht 100%.
Komisch, dann solltest du einfach mal einen GC verwenden, der nicht
buggy ist.
(Und natürlich eine passende Sprache, bei C hast du immer
Einschränkungen mit den dort möglichen konservativen GCs)
Peter II schrieb:> Fast jede javaanwendung hat ein Speichleck. Je länger sie laufen, desto> mehr Speicher wird verwendet.>> Bei einfachen Objekten mag das ja noch alles gehen, aber sobald> resourcen verwendet werden (files, Schriftarten, threads), klappt das> einfach nicht.
Ein GC verhindert nicht alle Speicherlecks, genausowenig wie selber den
Speicher zu verwalten, nur muss man mit einem GC weniger darauf achten
wo ich einen String erzeugt habe und wo ich ihn dann aufraeumen muss.
Es ist IMHO schon mal ein Schritt in die richtige Richtung auf
"nicht-embedded Systemen" einen GC zu verwenden, falls Entwicklungszeit
eine Rolle spielt.
Michael schrieb:> Es gibt seit> Jahrzehnten speziell für den Embedded-Bereich entwickelte GCs, die nicht> nur berechenbar sind, sondern sogar Echtzeitgarantien geben.
einen Namen dazu?
dumdi dum schrieb:> Michael schrieb:>> Es gibt seit>> Jahrzehnten speziell für den Embedded-Bereich entwickelte GCs, die nicht>> nur berechenbar sind, sondern sogar Echtzeitgarantien geben.>> einen Namen dazu?Michael schrieb:> Ist nicht wirklich mein Gebiet, aber ich weiß, daß Harlequin das hatte.> Mittlerweile heißen die LispWorks.
Ich kann mir das kaum vorstellen, weil LispWorks eigentlich nicht für
Embedded Anwendungen gedacht ist. F
Magst Du da nicht mal nachforschen ? Wäre sehr interessant.
Grüße
Andreas
Peter II schrieb:> Fast jede javaanwendung hat ein Speichleck. Je länger sie laufen, desto> mehr Speicher wird verwendet.
Ich hab eine ähnliche Erfahrung mit einem C# Programm gemacht, in deren
Weiterentwicklung ich vor Jahren mal eine Zeit lang involviert war.
Es war eigentlich keine großartige Sache, trotzdem präsentierte sich das
System so, dass man beim Hochfahren der Applikation im Taskmanager
zusehen konnte, wie die MB in die Höhe kletterten. Nach einigen Stunden
gab die Applikation dann mit einem 'Out of Memory' auf.
Wie gesagt, war keine großartige Sache, ein paar dynamische Listen, in
die immer wieder mal Einträge dazu kamen, aber auch im Zuge der
Abarbeitung wieder wegkamen. Das waren Störungsmeldungen von
Gebäudemanagment-Steuerungen, die gesammelt, klassifiziert und je nach
Situation an diverse Abnehmer verteilt wurden. Mit C++,
Standardcontainern und den RAII Konzept keine großartige Sache in der
Speicherverwaltung, aber in C# kam es da wohl zu irgendwelchen
gegenseitigen Blockaden, so dass der GC den Speicher nicht mehr
vollständig aufgeräumt hat. Jedenfalls hat das Suchen nach den Ursachen
einiges an Zeit verschlungen (hab nicht ich gemacht). Mehr Zeit als ein
ganz einfacher RAII Ansatz in C++ gekostet hätte.
> Das und Generationskonflikte.. ;)> Die alte Laier von "Derjenige der weiss was er macht, braucht das nicht"
Da hast du nicht ganz unrecht.
Für meinen Teil kann ich sagen: Ich vermisse einen GC nicht und komm
auch ohne ganz gut zurecht.
Karl Heinz schrieb:> Jedenfalls hat das Suchen nach den Ursachen> einiges an Zeit verschlungen (hab nicht ich gemacht). Mehr Zeit als ein> ganz einfacher RAII Ansatz in C++ gekostet hätte.
Wenn ich mit einem Hammer schneller bin als mit einer Nagelpistole,
liegt das Problem sehr wahrscheinlich nicht an der Nagelpistole, sondern
daran wie ich sie nutze ;)
Mna kann alles falsch bedienen, d.h. aber nicht, dass das Werkzeug
fehlerhaft ist.
Mladen G. schrieb:> Karl Heinz schrieb:>> Jedenfalls hat das Suchen nach den Ursachen>> einiges an Zeit verschlungen (hab nicht ich gemacht). Mehr Zeit als ein>> ganz einfacher RAII Ansatz in C++ gekostet hätte.>> Wenn ich mit einem Hammer schneller bin als mit einer Nagelpistole,> liegt das Problem sehr wahrscheinlich nicht an der Nagelpistole, sondern> daran wie ich sie nutze ;)>> Mna kann alles falsch bedienen, d.h. aber nicht, dass das Werkzeug> fehlerhaft ist.
Da stimme ich dir durchaus zu.
Wenn allerdings das Werkzeug 'Nagelpistole' als das Beste seit
geschnittenem Brot beworben wird und sich dann ganz offensichtlich in
der Praxis rausstellt, das nicht alles Gold ist was glänzt und es einem
nicht davon entbindet mitzudenken und aufzupassen (was aber keiner
wahrhaben will), dann komm ich auch mit meinem bewährten Werkzeug
'Hammer' durchaus klar und benutzte den lieber. Vor allen Dingen dann,
wenn der Hammer mir dann auch noch einen Nagelauszieher mitliefert, den
ich mit einer Nagelpistole nicht habe (ich spiele damit auf Destruktoren
an, die in C++ zuverlässig zum Aufräumen benutzt werden können,
zumindest in C# jedoch völlig nutzlos sind)
> Das und Generationskonflikte.. ;)> Die alte Laier von "Derjenige der weiss was er macht, braucht das nicht"
Da hast du nicht ganz unrecht.
Für meinen Teil kann ich sagen: Ich vermisse einen GC nicht und komm
auch ohne ganz gut zurecht.
Mladen G. schrieb:> Mna kann alles falsch bedienen, d.h. aber nicht, dass das Werkzeug> fehlerhaft ist.
wenn bei dem Werkzeug aber nicht offensichtlich ist wie man es bedienen
soll, das ist das Werkzeug daran schuld.
Ist wie bei einen Fernseher, wenn ich erst in der Doku nachlesen muss
wie ich ihn einschalten kann, das ist nicht praxistauglich.
Karl Heinz schrieb:> Für meinen Teil kann ich sagen: Ich vermisse einen GC nicht und komm> auch ohne ganz gut zurecht.
Hat alles seine Vor- und Nachteile. GCs kamen auf, weil die
Speicherverwaltung von C/C++ den Leuten über den Kopf wuchs. Mit
Programmen, die auch sehr gerne Lecks hatten oder Speicher doppelt
freigaben.
Ist das Ei des Kolumbus mittlerweile erfunden?
Karl Heinz schrieb:>> Das und Generationskonflikte.. ;)>> Die alte Laier von "Derjenige der weiss was er macht, braucht das nicht"> Da hast du nicht ganz unrecht.> Für meinen Teil kann ich sagen: Ich vermisse einen GC nicht und komm> auch ohne ganz gut zurecht.
Ich sage mal so, mit GC suche ich jetzt zumindest nicht mehr die
Speicherleaks anderer :-), und entgegen Peter II's Aussagen, laufen bei
uns sogar in Java programmierte Mutithreaded Server in
Finanzanwendungen, die wochenlang nicht runtergefahren werden.
Und ein Destruktor nützt halt nichts, wenn er nicht aufgerufen wird.
Genausowenig wie ein GC was freigeben kann, wenn das Programm es noch
benutzt, bzw Referenzen davon nicht freigegeben werden.
Karl Heinz schrieb:> Wenn allerdings das Werkzeug 'Nagelpistole' als das Beste seit> geschnittenem Brot beworben wird und sich dann ganz offensichtlich in> der Praxis rausstellt, das nicht alles Gold ist was glänzt und es einem> nicht davon entbindet mitzudenken und aufzupassen, dann komm ich auch> mit meinem bewährten Werkzeug 'Hammer' durchaus klar.
Da stimme ich völlig zu.
Karl Heinz schrieb:> Da stimme ich dir durchaus zu.> Wenn allerdings das Werkzeug 'Nagelpistole' als das Beste seit> geschnittenem Brot beworben wird und sich dann ganz offensichtlich in> der Praxis rausstellt, das nicht alles Gold ist was glänzt und es einem> nicht davon entbindet mitzudenken und aufzupassen (was aber keiner> wahrhaben will), dann komm ich auch mit meinem bewährten Werkzeug> 'Hammer' durchaus klar.
Naja, Marketing hat auch immer Einfluss.. Java war die Sprache die vom
Marketing als Sprache beworben wurde, die keine Zeiger hat, und damit
viele Probleme vermeidet.
Woher kommen denn dann diese NullPointerExceptions? ;)
Da haben die Entwickler nicht schnell genuig mit dem Marketinggefasel
mitgehalten und sind nichtmehr dazu gekommen es in
"NullReferenceException" umzubennen.
Selbst mit GC kann man immer noch Speicherlecks haben.
Karl Heinz schrieb:>> Das und Generationskonflikte.. ;)>> Die alte Laier von "Derjenige der weiss was er macht, braucht das nicht"> Da hast du nicht ganz unrecht.> Für meinen Teil kann ich sagen: Ich vermisse einen GC nicht und komm> auch ohne ganz gut zurecht.
Ach, das geht ja nicht erst beim GC los.
Habe bei einem fruehren AG in der Kantine oefters Diskussionen ala "Wozu
eigentlich OO und C++? Ging doch auch alles mit C und prodzedural.
Diejenigen die wissen was sie machen, brauchen das nicht."
Diese Diskussionen gab es schon vor 30 Jahren, damals ging es allerdings
um Assembler vs C, "Wozu eigentlich Hochsprachen? Diejenigen die wissen
was sie machen, koennen das in Assembler viel besser.."
Ich bin Java Entwickler seit ueber 14 Jahren, arbeite seit 12 Jahren mit
Eclipse, mich bringt keiner dazu zu IntellJ zu wechseln :D
Peter II schrieb:> wenn bei dem Werkzeug aber nicht offensichtlich ist wie man es bedienen> soll, das ist das Werkzeug daran schuld.
Ist aber gerade bei Java jetzt nicht wirklich der Fall. Der funktioniert
automatisch und seit spätestens 1.5 ziemlich gut.
Udo Schmitt schrieb:> Ist aber gerade bei Java jetzt nicht wirklich der Fall. Der funktioniert> automatisch und seit spätestens 1.5 ziemlich gut.
leider nicht. Wir haben bei uns einige Tomcat Anwendungen, und diese
müssen einmal in der Woche neu gestartet werden, sonst müsste man
Unmengen an Speicher in den Server stecken.
Andreas H. schrieb:> Magst Du da nicht mal nachforschen ? Wäre sehr interessant.
Ja, mag ich. Aber eben hatte ich kein Glück damit.
Komisch. Irre ich mich mit Harlequin? Oder haben die das aufgegeben?
Peter II schrieb:> leider nicht. Wir haben bei uns einige Tomcat Anwendungen, und diese> müssen einmal in der Woche neu gestartet werden, sonst müsste man> Unmengen an Speicher in den Server stecken.
Der GC hilft natürlich nur, wenn man Referenzen auf Speicher auch
irgendwann mal wieder aufgibt.
Oder wie stellst du dir das vor?
"Super, meine dreißig Gigabyte Daten kann ich wunderbar in den RAM
einlesen. Mein hochoptimierter GC behält immer nur die letzten zwei
Gigabyte und wirft den Rest weg." ;-)
Michael schrieb:> Der GC hilft natürlich nur, wenn man Referenzen auf Speicher auch> irgendwann mal wieder aufgibt.
die Frage ist wie man es schafft immer die Referenz freizugeben.
z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.
Wann räumt der GC das nun auf?
Noch schlimmer ist wenn man mit sehr großen Datenmengen arbeitet, dann
hilft es auch nicht die Referenz zu löschen. Dann muss man den GC
teilweise von Hand aufrufen, damit man den Speicher gleich wieder
verwenden kann, weil der GC sonst erst später aufräumen will.
Bei C(C++) muss ich ihn zwar von Hand freigeben, weiß aber das er dann
auch wirklich frei ist.
Peter II schrieb:> leider nicht. Wir haben bei uns einige Tomcat Anwendungen, und diese> müssen einmal in der Woche neu gestartet werden, sonst müsste man> Unmengen an Speicher in den Server stecken.
Bei sowas gibt es ja zwei Möglichkeiten:
- Auf den bösen GC schimpfen der ja nix kann
- Mal mit einem passendem Tool (z.B. JProfiler) sich mal ansehen welche
Objekte da immer mehr Speicher verbrauchen und den Bug fixen
Peter II schrieb:> Noch schlimmer ist wenn man mit sehr großen Datenmengen arbeitet, dann> hilft es auch nicht die Referenz zu löschen. Dann muss man den GC> teilweise von Hand aufrufen
NEEEIN! Bitte nicht, das ist erstens Unnötig und Verschlechtert zweitens
die Performance und ist drittens nicht garantiert da überhaupt etwas
passiert...
Läubi .. schrieb:> Mal mit einem passendem Tool (z.B. JProfiler) sich mal ansehen welche> Objekte da immer mehr Speicher verbrauchen und den Bug fixen
ist nicht von uns die Anwendung, also kein Quelltext vorhanden. Damit
bringt es auch wenig wenn ich den Fehler finden würde.
Peter II schrieb:> ist nicht von uns die Anwendung, also kein Quelltext vorhanden
Bugreport? Jammern über Fehler die man nie meldet bringt ja wohl noch
weniger...
Michael schrieb:> Komisch. Irre ich mich mit Harlequin? Oder haben die das aufgegeben?
ALso bei Harlequin bin ich mir nicht sicher. Aber bei LispWorks ist mir
nie aufgefallen, dass die auch Embedded Versionen haben.
Vielleicht hat Dave das bei der Übernahme rausgeworfen ?
Der GC der Windows Version war aber schon nice.
Mladen G. schrieb:> Das und Generationskonflikte.. ;)> Die alte Laier von "Derjenige der weiss was er macht, braucht das nicht"
Appropos:
Der LispWorks GC ist ein Generational-GC und macht (meist) keine
Probleme.
Aber falls Du die Generation der Hacker meintest:
GCs wurden schon in Sprachen eingesetzt (z.B. Lisp, Smalltalk) als die
einzige Anwendung von Java noch "mahlen und mit heissem Wasser
aufkochen" war.
Von daher ist das für diese (Hacker-)Generation eher kalter Kaffee ;-)
Grüße
Andreas
Peter II schrieb:> z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.> Wann räumt der GC das nun auf?
Im Gegensatz zu Referenzzählern können GCs damit problemlos umgehen.
Wenn die beispielsweise ausgehend von einem Wurzelobjekt Links nur in
Objekten berücksichtigen, die sie bereits kennen. Tote Strukturen, die
nur auf sich selbst verweisen, fallen dabei automatisch raus.
Peter II schrieb:> z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.> Wann räumt der GC das nun auf?
Wenn von außen niemand eines der Objekte referenziert, wird der ganze
Zykel abgeräumt. Es muss immer eine Verbindung zur Wurzel bestehen.
Hobbyist schrieb:> Wenn von außen niemand eines der Objekte referenziert, wird der ganze> Zykel abgeräumt. Es muss immer eine Verbindung zur Wurzel bestehen.
so einfach ist das glaube ich nicht. Dann würde der GC ein Threadobjekt
auch wegschmeißen.
Peter II schrieb:> die Frage ist wie man es schafft immer die Referenz freizugeben.>> z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.>> Wann räumt der GC das nun auf?
Er räumt immerhin auf, ohne musst du alles aufräumen indem du es von
Hand freigibst. Solange die Werte benutzt werden und in der Liste sind
kann der GC natürlich nichts freigeben, solange kannst du Objekte auch
nicht in C++ oder C freigeben
Peter II schrieb:> Noch schlimmer ist wenn man mit sehr großen Datenmengen arbeitet, dann> hilft es auch nicht die Referenz zu löschen. Dann muss man den GC> teilweise von Hand aufrufen, damit man den Speicher gleich wieder> verwenden kann, weil der GC sonst erst später aufräumen will.
Er räumt spätestens dann auf, wenn er Speicherprobleme bekommt. Und ja
man kann ihn auch manuell aufrufen wenn man weiß jetzt habe ich eh etwas
Zeit...
Peter II schrieb:> Bei C(C++) muss ich ihn zwar von Hand freigeben, weiß aber das er dann> auch wirklich frei ist.
Du kannst in Java bei komplexeren Strukturen Pointer explizit nullen und
so dem GC das Leben einfacher machen, aber es funktioniert auch
erstaunlich gut ohne.
Wir benutzen Java auch um XML Dateien, die mehrere GByte groß sind zu
parsen, mit Daten aus einer Datenbank einen Vollabgleich zu fahren und
ggf in die Datenbank zu speichern. Da werden viele GByte an Speicher
alloziert und wieder weggeworfen, alles ohne Probleme und ohne manuelle
Nachhilfe, es geht also.
Und das Schönste: Es geht mit einer Lib auf Sun, Aix, allen Linux
Derivaten, Windows.
Und auf allen diesen Systemen mit DB/2, Oracle und MS-SQL ohne daß ich
eine Zeile spezifischen Code schreiben musste und ohne daß wir für jede
Betriebssystem/Datenbank Kombination eine extra Auslieferungsversion
compilieren/linken, archivieren und nicht zuletzt testen müssen!
Peter II schrieb:> so einfach ist das glaube ich nicht. Dann würde der GC ein Threadobjekt> auch wegschmeißen.
Nein, denn irgendwo gibts garantiert eine Liste aller Threads. Und diese
Liste wiederum irgendwo anders, und ... und irgendwann bist du an der
Wurzel. So jedenfalls läuft das in jenen Sprachen, wo GC herkommt, wie
Lisp oder Smalltalk.
Es entbehrt nicht einer gewissen Komik, ausgerechnet das klassischste
aller Beispiele für GC und gegen Referenzzähler gegen GC in Stellung
bringen zu wollen.
Peter II schrieb:> z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.>> Wann räumt der GC das nun auf?
Du meinst bei Objekten die auf sich selbst referenzieren? Na das wird
aufgeräumt wenn der GC läuft. Such einmal nach "Tracing garbage
collectors". Nur die billigsten GCs sollten darauf hineinfallen.
> Noch schlimmer ist wenn man mit sehr großen Datenmengen arbeitet, dann> hilft es auch nicht die Referenz zu löschen. Dann muss man den GC> teilweise von Hand aufrufen, damit man den Speicher gleich wieder> verwenden kann, weil der GC sonst erst später aufräumen will.
Das ist wohl ein spezieller Spezialfall und wenn das wirklich der Fall
ist, dann ist auch manueller GC-Aufruf kein Beinbruch. Im Normalfall ist
das Environment aber so intelligent selbst zu merken, dass es jetzt
aufräumen muss. Ich habe zumindest noch nie einen manuellen Aufruf
benötigt.
> Bei C(C++) muss ich ihn zwar von Hand freigeben, weiß aber das er dann> auch wirklich frei ist.
Was dir nicht viel bringt außer eventuell ein gutes Gewissen.
Peter II schrieb:> z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.>> Wann räumt der GC das nun auf?
Wenn er Zeit dazu hat ;) Normalerweise ist das kein Problem so was
aufzuräumen/freizugeben. Der GC sucht bspw. von sogenannten GC roots
(lokalen Variablen, statischen Variablen etc.) ausgehend auf was diese
verweisen. Alles was nicht erreicht werden kann, kann freigegeben
werden.
> Bei C(C++) muss ich ihn zwar von Hand freigeben, weiß aber das er dann> auch wirklich frei ist.
Frei schon, aber nicht zwingend nutzbar (Fragmentierung...)
Peter II schrieb:> Warum wird ein Filehandle nicht vom GC aufgeräumt wenn keine Referenz> mehr da ist? Die Datei bleibt ewig geöffnet.
Die überschreitest damit die Grenze von Anwenderprogramm und
Betriebssystem. GC gilt nicht systemweit, sondern ist auf die
Anwendungsebene des Prozesses begrenzt. Filehandles als API-Elements
eines Betriebssystems sind somit nicht automatisch Teil eines GC
Mechanimusses des Anwenderprogramms.
Wenn man in der betreffenden Sprache einen Wrapper um das Handle baut,
um ein Sprachobjekt daraus zu zimmern, dann kann man diesem Wrapper eine
Aufräum-Methode verpassen, die spätestens mit Freigabe des Wrappers im
GC das Handle schliesst. So das gewollt ist.
Peter II schrieb:> die Frage ist wie man es schafft immer die Referenz freizugeben.>> z.b. eine Verkette Liste wo das Ende auf den Anfang zeigt.
Da gibt es die verschiedensten Ansätzte (mark & sweep und wie die alle
heissen). Das ist für einen modernen GC nun kein Problem.
Voraussetzung dafür ist aber, dass es ausserhalb der Kette keine
Referenz mehr auf irgend ein Element der Kette gibt. Das liegt dann aber
in der Verantwortung des Entwicklers.
Die Ursache in Memory Leaks kommen häufig daher, dass mit Frameworks
gearbeitet wird, die von den Entwicklern zuwenig genau verstanden werden
(z.B. liefert ein getElement() nun eine Refernz oder eine Kopie?
Speichert ein putElement() eine Referenz oder eine Kopie?).
> Wann räumt der GC das nun auf?
Das ist ein sehr heikler Punkt. Auch hier gibt es verschiedenste
Strategien (wenn der Speicher zu 90% aufgebraucht ist, nach x ms, nach x
Maus-Events, etc.). Ein anderer interessanten Punkt ist, ob immer
vollständig aufgeräumt wird (kann lange dauern) oder nur eine maximale
Zeit lang (ist sehr viel komplexer).
==> GC an sich funktioniert heute sehr gut und kann auch sehr gut auf
die Rahmenbedingungen ausgerichtet werden. Es schützt aber nicht davor,
dass ein schlechter Entwickler schlechte Software schreibt.
Gruss
Claude
PS: Ich kenne komplexe Server-Applikationen, mit denen rund um die Uhr
sehr viele Leute arbeiten, die monatelang nicht herunter gefahren
werden.
Nachdem ich es auf meinem ersten Computer geschafft habe, ein
Basic-Programm immer wieder für jeweils ca. 2s in der GC verharren
zu lassen, war für mich GC auch böse :)
Mittlerweile, auf moderneren Computern mit moderneren
Programmiersprachen und Laufzeitsystemen, machen sich die von der GC
verursachten Unregelmäßigkeiten im Programmablauf kaum noch bemerkbar.
Deswegen mag ich für die High-Level-Programmierung ganz gerne auch
wieder Sprachen mit GC.
Man muss sich aber eben bewusst sein, dass GC zwar ungültige Pointer und
mehrfache Freigaben perfekt verhindert, nicht aber Speicherlecks. Die
Verhinderung von Speicherlecks wird zwar von der GC bis zu einem
gewissen Grad unterstützt, bleibt aber ohne Mitdenken des Programmierers
erfolglos. In dem von A. K. verlinkten Artikel
http://acadopus.de/java/die-typischen-faelle-von-memory-leaks-in-java-anwendungen_4002.html
gibt es schöne Beispiele dafür.
Das nach wie vor bestehende Problem der GC: Um Speicherlecks zu
vermeiden, muss der Programmierer ziemlich genau wissen, wie
Bibliotheksfunktionen den Speicher nutzen und wo möglicherweise
versteckte Referenzen auf Objekte gehalten werden. Bei den immer größer
werdenden Laufzeit- und anderen Bibliotheksfunktionen ist es aber nahezu
unmöglich, diesbezüglich den erforderlichen Überblick zu behalten.
Bei den klassichen auf malloc() und free() basierenden Systemen ist das
vergleichsweise einfach: Normalerweise gibt diejenige Programmeinheit,
die Speicher anfordert, diesen auch wieder zurück. Ist dies nicht
möglich (bspw. wenn eine Funktion ein dynamisch angelegtes Objekt an den
Aufrufer zurückgibt), dann ist dies in der Dokumentation vermerkt
zusammen mit Hinweisen, wann und wie der Speicher wieder freigegeben
werden soll. Das funktioniert aber natürlich auch nur dann, wenn die
Dokumentation entsprechend vollständig ist und vom Programmierer auch
gelesen wird. In beide Bereichen gibt es noch Defizite.
Peter II schrieb:> ist nicht von uns die Anwendung, also kein Quelltext vorhanden. Damit> bringt es auch wenig wenn ich den Fehler finden würde.
Das ist aber jetzt schon ganz hart am Getrolle. Da hat jemand ein
Memory-Leak fabriziert und daher ist der GC schuld und unnötig. Als ob
der Programmierer in C++ nicht noch ein viel größeres Memory-Leak
produziert hätte.
Das Einzige was man dem GC hier vorwerfen kann ist, dass der
Programmierer die Anwendung in C++ ev. gar nicht stabil bekommen hätte
und daher ein fähigerer Programmierer oder mehr Zeit notwendig gewesen
wären.
Läubi .. schrieb:> NEEEIN! Bitte nicht, das ist erstens Unnötig und Verschlechtert zweitens> die Performance und ist drittens nicht garantiert da überhaupt etwas> passiert...
Ja leider ist das manchmal halt leider nicht vermeidbar. Ich kenn das
von C# wenn man mit großen Arrays arbeitet und zb 1000MB freigibt und
gleich in der nächsten Instruktion 1500MB allokiert. Ohne manuelles
Aufrufen von GC.Collect(), wurde der Speicher nicht schnell genug
freigegeben und führte zwangsläufig zu einer Out-Of-Memory Exception auf
meinem Rechner. Auch wenn man die Referenzen auf NULL setzt, in solchen
Fällen räumt die GC oft nicht schnell genug auf.
Mittlerweile schreibe ich speicherintensive Programme aber ohnehin
lieber wieder in C++. Das macht auch wieder mehr Spaß wenn man am Ende
bis aufs letzte optimiert.
Yalu X. schrieb:> Bei den klassichen auf malloc() und free() basierenden Systemen ist das> vergleichsweise einfach: Normalerweise gibt diejenige Programmeinheit,> die Speicher anfordert, diesen auch wieder zurück.
Das führt freilich zum umgekehrten Extrem. Wenn Code von Modul A einen
Link auf ein Objekt von Modul B speichert, ohne dass der Programmierer
das weiss, dann gibts bei GC ein scheinbares Speicherleck - wie im Link
beschrieben - und bei malloc/free einen Sprung ins Nichts. Such es dir
aus. ;-)
Jan Hansen schrieb:> Das ist aber jetzt schon ganz hart am Getrolle. Da hat jemand ein> Memory-Leak fabriziert und daher ist der GC schuld und unnötig
wo habe ich geschrieben das der GC daran schuld ist? Mir ist nur
aufgefallen das wachsender Speicherverbrauch häufig bei Java auftritt.
Ob das nun am GC liegt oder nicht kann ich nicht sagen.
Arc Net schrieb:> Der GC sucht bspw. von sogenannten GC roots> (lokalen Variablen, statischen Variablen etc.) ausgehend auf was diese> verweisen.
es werden also ständig versucht alle Objekte zu Prüfen ob sie
weggeschmissen werden können - kein Wunder warum Java Programm so
langsam sind
(Kommentar nicht 100% erst gemeint, gibt es werte wie viel CPU zeit der
GC alleine braucht? )
Peter II schrieb:> es werden also ständig versucht alle Objekte zu Prüfen ob sie> weggeschmissen werden können - kein Wunder warum Java Programm so> langsam sind
Ja, das ist ein Nebeneffekt. GC benötigt auch temporären Speicher. Die
Alternativen haben freilich auch Nebeneffekte. So entsteht
beispielsweise durch Referenzzähler ebenfalls Zusatzaufwand, in Platz
und Zeit, aber anders verteilt.
Hi,
Hobbyist schrieb:> Achso, das bezog sich also ausschließlich auf µC-Anwendungen.
Nein, das bezieht sich auf so ziemlich alle zeitkritischen Anwendungen.
Wir stellen eine Echtzeit-Betrugserkennung bei Kreditkartenzahlungen
her; dabei ist die Garbage Collection ein Dauerthema.
Liebe Grüße,
Karl
Karl Käfer schrieb:> Nein, das bezieht sich auf so ziemlich alle zeitkritischen Anwendungen.
Der GC lässt sich ja auch manuell steuern. In zeitkritischen
Codeabschnitten kann er auch deaktiviert werden.
Zudem läuft der GC ja üblicherweise nebenläufig, so dass die anderen
Threads davon nichts mitbekommen (es sei denn man hat nur einen Kern
;-))
Jan Hansen schrieb:> Als ob der Programmierer in C++ nicht noch ein viel größeres Memory-Leak> produziert hätte.
Dem wäre statt dessen wahrscheinlich das Programm weggeflogen. Mit einem
schönen sauberen Crash. Statt Tag für Tag langsamer zu werden, bis der
Server aus Speichermangel die Grätsche macht.
Karl Käfer schrieb:> Nein, das bezieht sich auf so ziemlich alle zeitkritischen Anwendungen.> Wir stellen eine Echtzeit-Betrugserkennung bei Kreditkartenzahlungen> her; dabei ist die Garbage Collection ein Dauerthema.
Wir machen hier etwas sehr aehnliches, der GC ist aber nicht unser
Problem, sondern die Queries die von Hibernate generiert werden und
damit die Oracle DB so langsam machen dass die sich nicht mehr vor dem
Timeout meldet.
Parallelen GC anwerfen sollte zumindest nicht die ganze VM einfrieren
bei einem GC run.
Hobbyist schrieb:> Zudem läuft der GC ja üblicherweise nebenläufig, so dass die anderen> Threads davon nichts mitbekommen (es sei denn man hat nur einen Kern
Es ist nicht ganz so einfach, eine GC so zu bauen, dass sie ohne
grössere Aufwirkungen auf andere Threads bleibt. Der Link zur Davik/ART
Migration erwähnt auch diese Problematik. So wird darin die
GC-Implementierung von Dalvik als einer der Gründe für Ruckler in
Android gesehen.
Peter II schrieb:> es werden also ständig versucht alle Objekte zu Prüfen ob sie> weggeschmissen werden können - kein Wunder warum Java Programm so> langsam sind> (Kommentar nicht 100% erst gemeint, gibt es werte wie viel CPU zeit der> GC alleine braucht? )
Wie schon geschrieben wurde, kommt es auf die konkrete Implementierung
des GCs an z.B. Mark&Sweep
http://en.wikipedia.org/wiki/Mark_and_sweep
In den Links oben zu Echtzeit-GCs sollte sich auch einiges finden
lassen.
Interessante Ansätze für Echtzeit-GCs auf FPGAs z.B.:
Parallel Real-time Garbage Collection of Multiple Heaps in
Reconfigurable Hardware, Bacon, Cheng, Shukla, 2014
http://dl.acm.org/citation.cfm?id=2602996
A. K. schrieb:> Karl Heinz schrieb:>> Für meinen Teil kann ich sagen: Ich vermisse einen GC nicht und komm>> auch ohne ganz gut zurecht.>> Hat alles seine Vor- und Nachteile. GCs kamen auf, weil die> Speicherverwaltung von C/C++ den Leuten über den Kopf wuchs.
Ja, genau. Und denselben Leuten wächst jetzt statt der
Speicherverwaltung eben der Garbage Collector über den Kopf. Das kann
man als Fortschritt ansehen, muß man aber nicht.
Garbage Collection ist eine prima Sache, um die Entwicklerproduktivität
zu steigern. Dafür handelt man sich bei bestimmten Anwendungsfällen eben
neue Probleme ein.
Liebe Grüße,
Karl
A. K. schrieb:> Das führt freilich zum umgekehrten Extrem. Wenn Code von Modul A einen> Link auf ein Objekt von Modul B speichert, ohne dass der Programmierer> das weiss, dann gibts bei GC ein scheinbares Speicherleck - wie im Link> beschrieben - und bei malloc/free einen Sprung ins Nichts. Such es dir> aus. ;-)
Ja, hast recht, das kann natürlich auch passieren.
Vielleicht sollten wir einfach wieder zu den klassichen statischen
Sprachen wie Fortran≤77 zurückkehren. Fortran war damals so statisch,
dass man nicht einmal einen Stack brauchte. Und bei den heutzutage
typischen 16GiB Hauptspeicher kann man alle Arrays so groß
dimensionieren, dass ihre Grenzen erst erreicht werden, wenn ein
GC-basiertes Programm schon lange auf Grund von Speicherlecks mit einer
"memory full"-Exception ausgestiegen wäre ;-)
Yalu X. schrieb:> Und bei den heutzutage> typischen 16GiB Hauptspeicher
Mann was hätten wir vor 25 Jahren mit so viel Ram angefangen? Wir hätten
gar nicht gewusst was wir damit tun sollen :-)
dumdi dum schrieb:> Arc Net schrieb:>> benso ist eine manuelle Speicherverwaltung nicht perfekt. Stichworte>> u.a.: Heap fragmentation,>> Haben GCs nicht auch dieses Problem?
Wenn sie keine Heap Compaction machen, ja. Bspw. gibt es im aktuellen
.NET-GC einen Schalter mit dem im LOH (Large Object Heap) eine
Defragmentierung bei Bedarf erzwungen werden kann, Standardeinstellung
ist, dass dort keine durchgeführt wird. Im SOH (Small Object Heap) wird
es dagegen automatisch gemacht.
Peter II schrieb:> es werden also ständig versucht alle Objekte zu Prüfen ob sie> weggeschmissen werden können - kein Wunder warum Java Programm so> langsam sind
Erstens nicht ständig, sondern nur dann wenn der GC läuft.
Und auch da werden bei intelligenten Implementierungen nicht immer alle
Objekte geprüft. Da gibt es z.B. generationenbasierte Implementierungen.
Viele Objekte leben nämlich nur ganz kurz (z.B. in einer Schleife) - die
werden immer berücksichtigt. Lebt ein Objekt länger so wandert es
irgendwann in die nächste Generation und wird nur noch selten geprüft.
Es gibt nämlich nur wenige Objekte die eine mittlere Lebensdauer haben.
Wenn ein Objekt eine gewisse Lebensdauer erreicht hat, dann ist die
Wahrscheinlichkeit recht groß, dass es noch länger lebt.
Imho sollte man zwischen "Memory Leak" und "vergessenes Objekt"
unterscheiden.
Afaik sind memory leaks Speicherbereiche, die vom user/programm nicht
mehr verwendet werden können, D.h. der Speicher ist echt verloren (ich
adressiere hier komplexere Systeme, die noch ein OS untendrunter haben).
Bei vielen bisher geschilderten Problemen von OO-Sprachen mit GC geht es
aber primär um erhöhten Speicherverbrauch von Objekten, die noch
existieren und auch noch verwendet werden könnten, aber der Programmier
hat sie aus Schlampigkeit einfach vergessen.
Die andere Variante sind Systemressourcen unterhalb der VM, die vom GC
nicht erfasst werden und nicht geschlossen/abgebaut werden. Das können
aus dieser Sicht 'echte' Leaks sein, allerdings halt ohne GC-Kontext,
die VMs sind meistens in Sprachen ohne GC geschrieben.
Den meisten in
http://acadopus.de/java/die-typischen-faelle-von-memory-leaks-in-java-anwendungen_4002.html
genannten "Leaks" kann man durch einfache systematische Suche oder
Profilern auf die Schliche kommen.
Das gestaltet sich allerdings erheblich einfacher als die Suche nach
'echten' Leaks, weil ich systembedingt mehr Meta-Informationen zum
Speicher habe.