| Autor |
Nachricht |
jaenicke
      
Beiträge: 15840
Erhaltene Danke: 741
XP, W7 x64 (Chrome, IE9, FF), Debian, (OSX 10.7)
RAD XE 2, Java (NB), C++, C# (VS 2010), JS/HTML, PHP, Lazarus
|
Verfasst: Di 24.01.12 19:52
Martok hat folgendes geschrieben : | | Damit gearbeitet hab ich noch nicht, aber die Samples sehen sehr elegant aus - anders als man das von Delphi sonst kennt. |
So auf den ersten Blick sieht es ein wenig ähnlich wie das verlinkte Spring Framework aus, gerade im Hinblick auf das Registrieren von Interfaces. Aber ansonsten habe ich in den paar Beispielen, die ich jetzt angeschaut habe, nichts wirklich besonderes gesehen. So ähnlich sieht es auch mit Klassenmethoden und anonymen Methoden aus wie sie in den aktuellen Delphiversionen auch intern oft verwendet werden.
Hast du da vielleicht gerade ein Beispiel, das es sich lohnt näher anzuschauen? Das sind so viele... 
|
| |
|
|
Werbung ausblenden? Dann registriere Dich kostenlos.
Weitere Gründe für eine Registrierung.
Werbung ausblenden? Dann registriere Dich kostenlos.
Weitere Gründe für eine Registrierung.
|
|
delfiphan
       
Beiträge: 2682
Erhaltene Danke: 26
|
Verfasst: Di 24.01.12 23:43
baka0815 hat folgendes geschrieben : | | Was Nick Hodges da schreibt klingt nach: Nutze Interfaces und du brauchst dich nie wieder um die Laufzeit von Objekten kümmern. |
Das ist eine Illusion. Du kannst leicht zirkuläre Abhängigkeiten kriegen und so verhindern, dass Objekte jemals freigegeben werden und es kann passieren, dass Objekte zu früh freigegeben werden (z.B. bei Events, d.h. "Delegates"). Um das zu verhindern musst du in Delphi teilweise recht üble Hacks machen.
Einfaches Beispiel für ein Memory-Leak:
Ausserdem ist die Referenzzählung i.d.R. weniger effizient als ein GC, da bei jeder Zuweisung ein InterlockedIncrement gemacht werden muss.
Ein GC ist viel mächtiger. Ein GC kann in einem Wisch viele Objekte freigeben. Ein GC kann den Speicher defragmentieren. Ein GC kann verwaiste Gruppen erkennen, die sich gegenseitig zirkulär referenzieren und die ganze Gruppe freigeben. In C# hast du zudem schwache Referenzen und es ist nicht möglich, dass ein Objekt zu früh freigegeben wird.
|
| |
|
|
baka0815
      
Beiträge: 452
Erhaltene Danke: 10
Win XP, Debian GNU/Linux
Delphi 2007 Enterprise, Java, C#
|
Verfasst: Mi 25.01.12 12:44
delfiphan hat folgendes geschrieben : | baka0815 hat folgendes geschrieben : | | Was Nick Hodges da schreibt klingt nach: Nutze Interfaces und du brauchst dich nie wieder um die Laufzeit von Objekten kümmern. |
Das ist eine Illusion. |
Das habe ich vermutet oder zumindest befürchtet.
In TInterfacedObject wird ja kein Free ausgeführt, sondern ein Destroy. Das heißt dann ja auch, dass ich Instanzen auf Interfaces oder zumindest wenn ich von TInterfacedObject erbe, nicht selbst freigeben darf, richtig?
Ich kann mich dann also gar nicht mehr selbst darum kümmern. Es wird somit nur ein Problem (ich muss mich selbst drum kümmern) durch ein anderes (die Objekte kümmern sich selber - schlecht) ersetzt, oder?
|
| |
|
|
jaenicke
      
Beiträge: 15840
Erhaltene Danke: 741
XP, W7 x64 (Chrome, IE9, FF), Debian, (OSX 10.7)
RAD XE 2, Java (NB), C++, C# (VS 2010), JS/HTML, PHP, Lazarus
|
Verfasst: Mi 25.01.12 13:27
baka0815 hat folgendes geschrieben : | | Ich kann mich dann also gar nicht mehr selbst darum kümmern. |
Richtig. Solange die Referenzzählung aktiv ist, darfst du nichts mehr selbst freigeben.
Und das ist genau was ich aber manchmal möchte und was mich an C# und Java immer wieder stört wie gesagt. So schön die automatische Freigabe auch ist, wenn man das nicht auch selbst steuern kann (GC bei Java und C#) oder nur durch dreckige Tricks (Interfaces in Delphi), gibt es immer wieder Situationen wo man sich so richtig schön verrenken muss, damit die Automatismen arbeiten wie man es möchte.
|
| |
|
|
Martok
      

Beiträge: 2837
Erhaltene Danke: 182
Win 2000, Win XP
Delphi 7, Turbo Delphi Exp.
|
Verfasst: Mi 25.01.12 13:53
Ich muss mich grade ernsthaft verrenken, um eine Situation zu finden in der ich was selber freigeben will.
Wenn ich Speicher freigeben will, dann brauch ich den doch nicht mehr? Dann kann ich einfach die Referenz wegwerfen und der GC kümmert sich drum. Wenn ich die noch brauche, brauch ich die Daten dahinter aber auch noch... was programmierst du komisches?
Dass das in Delphi etwas kaputt ist stimmt aber. Wie eigentlich alles außer dem GUI-Designer. Aber ich schweife ab 
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Ich code EdgeMonkey -~==~- #ee-lounge in Freenode
|
| |
|
|
baka0815
      
Beiträge: 452
Erhaltene Danke: 10
Win XP, Debian GNU/Linux
Delphi 2007 Enterprise, Java, C#
|
Verfasst: Mi 25.01.12 14:07
Eigentlich mag ich das Konzept der GC ganz gerne und finde es teilweise nervig, dass ich mich in Delphi selbst drum kümmern muss.
Finde dann immer wieder Stolpersteine wie eine TStringList oder TObjectList die auf OwnsObjects=True gesetzt ist und ich somit versuche die Objekte doppelt freizugeben - was dann immer erst zu ewigen Suchen führt.
Dann sind da immer wieder stellen an denen man das try..finally doch vergessen hat und schon hat man ein Memory-Leak. Das kann passieren wenn man eben aus der Java- oder .NET-Welt kommt und die GC gewohnt ist.
Aber die Interface-Lösung von Delphi mit der internen Referenzzählung klingt dann ja auch nur erstmal nach 'ner guten Idee. Was mich auch stört ist, dass ich dann extra eine TInterfaceList brauche, mein Interface nicht auf eine Klasse casten kann und auch kein if (Intf is TObject) then machen kann, da das Interface ja kein TObject ist, auch wenn ich in dem konkreten Fall ja eine Instanz einer Klasse habe und wissen will, welche Klasse ich hier genau habe.
Kann man jetzt argumentieren, dass es sich dann um ein Designproblem meinerseits handelt, trotzdem finde ich das durchaus nervig...
@ jaenicke: Du kannst die GC in Java doch einfach manuell aufrufen - auch wenn man das nicht sollte.
|
| |
|
|
jaenicke
      
Beiträge: 15840
Erhaltene Danke: 741
XP, W7 x64 (Chrome, IE9, FF), Debian, (OSX 10.7)
RAD XE 2, Java (NB), C++, C# (VS 2010), JS/HTML, PHP, Lazarus
|
Verfasst: Mi 25.01.12 14:46
Martok hat folgendes geschrieben : | | Dann kann ich einfach die Referenz wegwerfen und der GC kümmert sich drum. |
Wenn es denn so wäre...
Ich hatte in einem Programm vor etwa einem halben Jahr in C# ca. 1,5 GiB RAM belegt, dann die Referenz auf diese Daten überschrieben und weitergemacht (in einer Schleife). Leider hat der GC aber nicht aufgeräumt, so dass nach wenigen Sekunden die Meldung kam, dass der Speicher voll sei.
Nach diversen Versuchen wie Auslagerung in eigene Methoden hatte ich es so gelöst, dass sich die Exe für jeden Durchlauf erneut selbst aufgerufen hat...
Dann habe ich es in Delphi gemacht und es lief sofort ohne Probleme und brauchte auch nur 1 GiB RAM maximal.
// EDIT:
baka0815 hat folgendes geschrieben : | | mein Interface nicht auf eine Klasse casten kann und auch kein if (Intf is TObject) then machen kann, da das Interface ja kein TObject ist, auch wenn ich in dem konkreten Fall ja eine Instanz einer Klasse habe und wissen will, welche Klasse ich hier genau habe. |
Doch, das geht. Ich weiß nicht ab welcher Delphiversion, aber mit den aktuellen Versionen (XE, XE2) auf jeden Fall. Ich schätze ab Delphi 2010, evtl. ab 2009.
|
| |
|
|
delfiphan
       
Beiträge: 2682
Erhaltene Danke: 26
|
Verfasst: Mi 25.01.12 19:13
jaenicke hat folgendes geschrieben : | Martok hat folgendes geschrieben : | | Dann kann ich einfach die Referenz wegwerfen und der GC kümmert sich drum. | Wenn es denn so wäre...
Ich hatte in einem Programm vor etwa einem halben Jahr in C# ca. 1,5 GiB RAM belegt, dann die Referenz auf diese Daten überschrieben und weitergemacht (in einer Schleife). Leider hat der GC aber nicht aufgeräumt, so dass nach wenigen Sekunden die Meldung kam, dass der Speicher voll sei. |
Das ist dann ziemlich sicher ein Bug in deinem C# Programm. Der GC in .NET ist nämlich ganz schön fleissig.
Du musst vor allem bei Events aufpassen. Denn Delegates, die man bei Events braucht, enthalten neben dem Methodenpointer auch eine starke Referenz auf das Objekt. In Delphi würdest du bei einem solchen Bug zwar den Speicher rechtzeitig freibekommen, würdest aber irgendwann mal eine AccessViolation kriegen. In .NET bleibt das Objekt halt am leben. Gibt aber gute Tools, die den ganzen Speicherbaum schön graphisch anzeigen können.
Wenn's was explizig zum Aufräumen gibt, verwende IDisposable. Dann hilft dir der Compiler bzw. FxCop auch immer schön, wenn du vergisst, aufzuräumen.
|
| |
|
|
baka0815
      
Beiträge: 452
Erhaltene Danke: 10
Win XP, Debian GNU/Linux
Delphi 2007 Enterprise, Java, C#
|
Verfasst: Mo 30.01.12 17:04
Sollte man in Delphi dann statt Interfaces abstrakte Klassen verwenden?
Dann muss ich mich zwar selber um den Speicher kümmern, habe aber die damit verbundenen Nachteile nicht.
Oder haben Abstrakte Klassen andere Nachteile - außer dass man diese instantiieren kann?
|
| |
|
|
delfiphan
       
Beiträge: 2682
Erhaltene Danke: 26
|
Verfasst: Mo 30.01.12 18:54
Eine abstrakte Basisklasse geht natürlich ein bisschen in die gleiche Richtung. Aber es gibt's keine Mehrfachvererbung, daher muss zuoberst in der Hierarchie immer diese abstrakte Klasse sein. Ein Interface kann man einfach an eine bestehende Klasse anhängen.
|
| |
|
|
|