Meine Application (ganz normal mit GUI) lädt eine Library1, welche wiederum eine Library2 lädt. Die Freigabe erfolgt folgendermaßen:
Form1.Destroy: Library1 wird unloaded
Library1.benutzte unit.finalization: Library1.Hauptobjekt.Free
Library1.Hauptobjekt.Destroy: Library2 wird unloaded
Library2.benutzte unit.finalization: Library2.Hauptobjekt.Free
Library2.Hauptobjekt.Destroy: DirectShow Interfaces freigeben
Ich habe in jeder Library ein funktionstüchtiges Log-System, welches zum Schluss in der Application ein Showmessage generiert. Wenn ich z.B. in den Destruktoren solche Logs einbaue, dann kommen allerdings nicht alle an. Da wird offenbar manches gekillt, bevor es fertig freigegeben wurde. Sichtbar wird das außerdem daran, dass DirectShow in Library2 nicht korrekt freigegeben wird und die Application beim Schließen abstürzt. Die Musik spielt zwar nicht weiter, aber das von DirectShow verwendete FFDShow erzeugt ein Symbol in der Systray, welches nach dem Absturz noch da ist und erst nach dem Killen der Application beim darüberfahren mit der Maus verschwindet. Wenn ich DirectShow vor dem Beenden stoppe, läuft alles nach Plan und mein Programm stürzt auch nicht ab. Daher denke ich, dass irgendwas an dem oben dargestellten Vorgehen fehlerhaft ist oder gar FPC da wieder irgend einen Bug hat.
Für Unwissende: DirectShow ist das Codecsystem von Windows und wird über COM Interfaces als IPC gesteuert.
Kaskade von Librarys wird nicht richtig freigegeben [gelöst]
-
- Beiträge: 462
- Registriert: Mi 30. Jul 2008, 13:11
- OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
- CPU-Target: 32Bit
- Kontaktdaten:
Kaskade von Librarys wird nicht richtig freigegeben [gelöst]
Zuletzt geändert von RSE am Mo 28. Dez 2009, 20:14, insgesamt 1-mal geändert.
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!
-
- Beiträge: 203
- Registriert: Di 22. Sep 2009, 13:08
- OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
- CPU-Target: xxBit
Re: Kaskade von Librarys wird nicht richtig freigegeben
Solche Probleme sind echt typisch... bei Media-Playern hatte ich da auch schon Pech.
Ein paar Sachen, die man eventuell machen kann:
1) Beim Freigeben darauf achten, dass vorher auch wirklich alle Interface-Referenzen entfernt worden sind.
Falls man aus dem Interface noch andere Interface-Referenzen auf Unter-Objekte gezogen hat, sollte man alle in der richtigen Reihenfolge eliminieren.
(Beispiel: Interface auf eine Text-Region aus einem MSWordDokument-Interface sollte entsorgt werden bevor man das Dokument-Interface entsorgt)
2) Darauf achten, dass nicht noch implizit versteckte Referenzen irgendwo auf dem Stack herumhängen.
Also: in einer Prozedur, in der ein Interface vernichtet wird, für alle Funktionsaufrufe, die Interfaces zurückliefern lokale Variablen verwenden (und selbst kontrolliert auf nil setzen).
3) unit.finalization / unit.initialization vermeiden
Konkrete Init() und CleanUp() Prozeduren verwenden und selbst aufrufen.
Damit hat man
a) den Zeitpunkt und die Reihenfolge besser im Griff
b) man kann besser testen ob es richtig funktioniert (auf 3x hintereinander)
Ein paar Sachen, die man eventuell machen kann:
1) Beim Freigeben darauf achten, dass vorher auch wirklich alle Interface-Referenzen entfernt worden sind.
Falls man aus dem Interface noch andere Interface-Referenzen auf Unter-Objekte gezogen hat, sollte man alle in der richtigen Reihenfolge eliminieren.
(Beispiel: Interface auf eine Text-Region aus einem MSWordDokument-Interface sollte entsorgt werden bevor man das Dokument-Interface entsorgt)
2) Darauf achten, dass nicht noch implizit versteckte Referenzen irgendwo auf dem Stack herumhängen.
Code: Alles auswählen
begin
Interface.GetSubInterface.Methode1();
// legt eventuell versteckt eine Referenz auf Interface.GetSubInterface in den Speicher
Interface := nil;
end; // <- hier erst wird die versteckte Referenz entsorgt
3) unit.finalization / unit.initialization vermeiden
Konkrete Init() und CleanUp() Prozeduren verwenden und selbst aufrufen.
Damit hat man
a) den Zeitpunkt und die Reihenfolge besser im Griff
b) man kann besser testen ob es richtig funktioniert (auf 3x hintereinander)
-
- Beiträge: 462
- Registriert: Mi 30. Jul 2008, 13:11
- OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
- CPU-Target: 32Bit
- Kontaktdaten:
Re: Kaskade von Librarys wird nicht richtig freigegeben
Also das mit den versteckten Referenzen möchte ich ausschließen, weil die Freigaben (soweit ersichtlich) alle wunderbar funktionieren, wenn man normal stoppt. Im Destruktor werden keine "neuen" Funktionen aufgerufen, der Code für die Freigabe der member-Variablen meiner Klasse, die die Referenzen auf die COM-Objekte halten, ist der gleiche wie beim normalen stoppen. Die Freigabereihenfolge stimmt auch, darauf hab ich geachtet.
Finalization habe ich extra gewählt, weil es auch dann aufgerufen wird, wenn die Library unvorhergesehen "unloaded" wird. Ein expliziter Aufruf einer Cleanup-Prozedur könnte aufgrund irgendwelcher unvorhergesehener Fehler schon eher nicht ausgeführt werden. Falls der Compiler korrekt arbeitet, sollte finalization doch die sicherere Alternative sein.
Ich vermute das Problem eher darin, dass der auszuführende Code aus irgendwelchen Gründen vorzeitig beendet wird oder aufgrund der fortgeschrittenen Beendung des Prozesses nicht mehr korrekt ausgeführt werden kann. Werden da irgendwelche Handles schon vor dem Aufruf von Destroy entfernt, dürfen innerhalb Destroy irgendwelche neuen Sachen nicht mehr initialisiert werden oder gibt es sonstige Einschränkungen, auf die man innerhalb Destroy achten muss? Ich denke da z.B. an die Fehlermeldung von Windows "Der Prozess kann nicht initialisiert werden, da die Arbeitsstation gerade heruntergefahren wird" oder so ähnlich, vielleicht gibt es ja ähnliches auch im Destroy...
Finalization habe ich extra gewählt, weil es auch dann aufgerufen wird, wenn die Library unvorhergesehen "unloaded" wird. Ein expliziter Aufruf einer Cleanup-Prozedur könnte aufgrund irgendwelcher unvorhergesehener Fehler schon eher nicht ausgeführt werden. Falls der Compiler korrekt arbeitet, sollte finalization doch die sicherere Alternative sein.
Ich vermute das Problem eher darin, dass der auszuführende Code aus irgendwelchen Gründen vorzeitig beendet wird oder aufgrund der fortgeschrittenen Beendung des Prozesses nicht mehr korrekt ausgeführt werden kann. Werden da irgendwelche Handles schon vor dem Aufruf von Destroy entfernt, dürfen innerhalb Destroy irgendwelche neuen Sachen nicht mehr initialisiert werden oder gibt es sonstige Einschränkungen, auf die man innerhalb Destroy achten muss? Ich denke da z.B. an die Fehlermeldung von Windows "Der Prozess kann nicht initialisiert werden, da die Arbeitsstation gerade heruntergefahren wird" oder so ähnlich, vielleicht gibt es ja ähnliches auch im Destroy...
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!
-
- Beiträge: 462
- Registriert: Mi 30. Jul 2008, 13:11
- OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
- CPU-Target: 32Bit
- Kontaktdaten:
Re: Kaskade von Librarys wird nicht richtig freigegeben
Ich hab jetzt die Lösung im MSDN gefunden. Dort heißt es über den Aufruf der DLLMain, in der mit großer Sicherheit auch die initialization und finalization Routinen abgearbeitet werden:
Ich muss also tatsächlich, wie von Patito vorgeschlagen, mit einer separaten Cleanup-Funktion vor dem Aufruf von UnloadLibrary arbeiten und darin alle COM-Interfaces freigeben.Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!