AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Reference Counting von TComponent

Ein Thema von dpc41 · begonnen am 13. Mär 2013 · letzter Beitrag vom 15. Mär 2013
Antwort Antwort
dpc41

Registriert seit: 13. Mär 2013
2 Beiträge
 
#1

AW: Reference Counting von TComponent

  Alt 14. Mär 2013, 15:20
Dank an alle für Links und Anmerkungen.

Leite ich TMyObject von TXMLDocument ab kommt kein Fehler, was nicht weiter überrascht, da TXMLDocument von TComponent erbt Übrigens bei beiden mit Owner = nil.

Hab den Test dank des Hinweises von Sir Rufo natürlich auch mit TInterfacedPersistent gemacht und erhalte die Access Violation.

Ich fasse zusammen: egal von was ich TMyObject ableite, in _addRef und _Release wir in allen Fällen Result := -1 gesetzt. Bei TObject, TinterfacedObject, TinterfacedPersistent kommt ein Fehler, bei TComponent und TXMLDocument keiner. Fehlererkennungsmechanismen wie Patito sie erwähnte, habe ich nicht, wobei ich nicht komplett sicher bin, was er damit meint. Der Code, der verwendet wird, ist oben gepostet, keine versteckten try-Blöcke, oder ähnliches.
Also wo ist der Unterschied? Hab mich schon durch die wildesten Assembler Stellen in den System Untits debuggt und finde nichts. Fakt ist die Zeile

CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release in

function _IntfClear(var Dest: IInterface): Pointer; der System.pas geht mal schief und mal nicht, was auch immer das bedeutet
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#2

AW: Reference Counting von TComponent

  Alt 14. Mär 2013, 16:12
Man muss 4 Fälle unterscheiden.
1.) Von TInterfacedObject abgeleitet
man darf nur den Interfacezeiger speichern und über das Interface auf das Objekt zugreifen
Delphi-Quellcode:
var
  test : IMyInterface; {Interfacezeiger}
  myobj : TMyInterfacedObject; {Objektzeiger}
begin
  // korrekte Anwendung
  test := TMyInterfacedObject.Create;
  test.Machwas;
  test := nil; // gibt das Objekt autom. frei
  
  // falsch
  myobj := TMyInterfacedObject.Create; // (*)
  test := myobj as IMyInterface;
  test.Machwas;
  myobj.MachwasAnderes; // gefährlich
  myobj.Free; // verboten!
Man sollte den Objektzeiger in diesem Fall gar nicht erst verwenden.
Das Problem entsteht in der Zeile die mit (*) markiert ist.
2.) Von TComponent abgeleitete Klasse (Owner=nil)
gleiche Regeln wie 1.)
3.) Von TComponent abgeleitete Klasse (Owner <> nil)
Man darf auf den Objektzeiger zugreifen
Manuelle Freigeben mit Free sollte man vermeiden (dies wird automatisch durch den Owner erledigt)
Wichtig: Bevor der Owner freigeben wurde und damit auch das Objekt, muss man alle Interfacezeiger auf nil setzen
oder die Interfacezeiger müssen zuvor "out-of-Scope" gekommen sein
4.) Klassen mit ausgeschalteter Referenzzählung
Bevor das Objekt freigeben wird, muss man alle Interfacezeiger auf nil setzen
oder die Interfacezeiger müssen zuvor "out-of-Scope" gekommen sein
  Mit Zitat antworten Zitat
Patito

Registriert seit: 8. Sep 2006
108 Beiträge
 
#3

AW: Reference Counting von TComponent

  Alt 15. Mär 2013, 08:03
Dank an alle für Links und Anmerkungen.

Ich fasse zusammen: egal von was ich TMyObject ableite, in _addRef und _Release wir in allen Fällen Result := -1 gesetzt. Bei TObject, TinterfacedObject, TinterfacedPersistent kommt ein Fehler, bei TComponent und TXMLDocument keiner. Fehlererkennungsmechanismen wie Patito sie erwähnte, habe ich nicht, wobei ich nicht komplett sicher bin, was er damit meint.
Deine Fehlermeldung kommt ja irgendwoher. Da du den Speicher nicht mit einem Speichermanager im Debug-Modus überprüfst, siehst du vermutlich nur die Access-Violation von Windows. Windows kann dir aber nicht alle Fehler mitteilen.

Der Speicher-Manager in deinem Programm holt sich von Windows immer ganze Pools von Speicher und gibt die dann auch nicht immer wieder direkt zurück an Windows, sondern behält eventuell den Speicher um ihn für andere Objekte zu verwenden. Somit kann dir Windows nicht immer eine Fehlermeldung geben wenn Du den Speicher anspringst. Die Größe des Objektes und die
aktuelle Ausrichtung im Speicher an Pool-Grenzen können dabei einen Unterschied machen.

Wie gesagt: Dein TComponent und dein TMyObject springen soweit ich sehe im _Release() beide freigegebenen Speicher an. Wenn man Glück hat ist der Speicher zurück an Windows gegeben worden und man bekommt eine Access-Violation. Wenn man Pech hat ist im Speicher irgendein anderes Delphi-Objekt und man ruft irgendeine zufällige Prozedur auf. Es kann auch sein, dass dort im Speicher noch die alte _Release Prozedur steht und nichts passiert.

Fazit: Ohne Debug-Tool für Speicherzugriffe kriegt man nicht wirklich mit was vor sich geht. Idealerweise sagt man da dem Speichermanager, dass er Speicher nicht wiederverwenden soll, und dass er beim Freigeben den Speicher so markieren soll, dass man einen Zugriff auf freigegebenen Speicher an irgendeinem Muster erkennen kann.

PS: Ich habe bei mir im Code das var vor deinen Referenzen weggeleassen (willst du da wirklich Klassen-Variablen haben?)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz