Einzelnen Beitrag anzeigen

Benutzerbild von sakura
sakura

Registriert seit: 10. Jun 2002
Ort: Unterhaching
11.412 Beiträge
 
Delphi 12 Athens
 
#2

Re: Der .NET Garbage Collector

  Alt 2. Dez 2004, 13:41
Interfaces in Delphi für Win32

Bevor ich auf die Interface von .NET eingehe, möchte ich noch einmal kurz die Interfaces erläutern, wie diese unter Delphi für Win32 durch Borland implementiert wurden.

Alle in Delphi erstellten Interfaces wurden unter Delphi von Delphi-Referenz durchsuchenIInterface abgeleitet. IInterface ist wie folgend deklariert:
Delphi-Quellcode:
type
  IInterface = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

  IUnknown = IInterface;
Uns interessieren jetzt besonders die Methoden _AddRef und _Release. Diese wurden von Delphi genutzt, um ein automatisches Referenz-Counting zu implementieren. Kurz heißt das, wann immer ein Objekt (ob TObject- oder IInterface-Abkömmlinge) einer Interface-Variablen zugewiesen wird, hat Delphi intern automatisch den Referenzzählen erhöht (_AddRef). Wenn immer eine Interface-Variable durch eine neues Objekt überschrieben wurde, bzw. mit nil gelöscht wurde, bzw. der Zugriffsbereich der Variable verlassen wurde, hat Delphi automatisch einen Aufruf zu _Release eingefügt. Wurde jetzt die letzte Referenz frei gegeben, _Release liefert den Wert 0 zurück, hat die Objekt-Implementierung von _Release das Objekt selbständig freigegeben. Das Standardbeispiel:
Delphi-Quellcode:
function TInterfacedObject._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;
Diese Vorgehensweise von Delphi hat das Arbeiten mit Interfaces sehr leicht gemacht, es hatte aber auch seine Tücken. Man sollte ein Objekt besser nie sowohl über Objekt-Variablen als auch über Interface-Variablen ansprechen. Sonst konnte es zu verschiedenen Zugriffsverletzungen (AV) kommen. Ein kurzes Beispiel:
Delphi-Quellcode:
var
  Obj: TSomeInterfacedObject;
  Intf: ISomeInterface;
[...]
Obj := TSomeInterfacedObject.Create;
Intf := Obj;
[...]
Obj.SomeMethod;
Intf.SomeInterfacedMethod;
Intf := nil;
[...]
Obj.SomeMethod;
[...]
In Zeile 5 erstellen wir ein Objekt vom Typ TSomeInterfacedObject, welches das Interface ISomeInterface implementiert. Jetzt wird in Zeile 6 der Variable Intf eine Referenz auf das Interface ISomeInterface, implementiert durch Obj übergeben. Hier erhöht Delphi automatisch den Interface-Referenz-Counter, dieser wird jetzt 1. Zur Zeit sind beide Instanzen (Obj und Intf) gültig. Somit ist der Zugriff in Zeile 8 auf Obj.SomeMethod kein Problem, genauso kann in Zeile 9 auch auf Intf.SomeInterfacedMethod; zugegriffen werden.

Nun wir in Zeile 10 der Interface-Verweis (Intf) auf nil gesetzt, also gelöscht. Delphi implementiert jetzt automatisch den Aufruf zu _Release und das Objekt dekrementiert seinen Referenz-Counter auf 0. Damit gibt es keine Interface-Variablen mehr, welche auf das Objekt verweisen und dieses gibt sich selbständig frei!

In Zeile 12 greifen wir mit obj.SomeMethod nun wieder auf das bereits zerstörte Objekt zu. Je nach Aktion ist der weitere Verlauf der Applikation jetzt unvorhersehbar. Im besten Falle erkennt Windows das Problem und meldet eine Zugriffsverletzung und bricht die aktuelle Verarbeitung mit einer Fehlermeldung ab.
Daniel Lizbeth