AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Freigabe eines Objektes wenn keine Referenz mehr drauf zeigt

Freigabe eines Objektes wenn keine Referenz mehr drauf zeigt

Ein Thema von Thebe · begonnen am 30. Sep 2005 · letzter Beitrag vom 30. Sep 2005
Antwort Antwort
Thebe

Registriert seit: 25. Jul 2004
Ort: Wedel
78 Beiträge
 
Delphi 6 Enterprise
 
#1

Freigabe eines Objektes wenn keine Referenz mehr drauf zeigt

  Alt 30. Sep 2005, 14:00
Hiho

Ich programmiere zur Zeit nen kleines 2D Spiel und benutze dafür Vektoren für die Position, Bewegung und Beschleunigung der einzelnen Spielelemente.
Für die unterschiedlichen Vektorenrechnungen brauch ich teilweise temporäre Vektoren für die Zwischenrechnungen und habe solangsam kein Bock mehr pro Methode wo Vektoren benötigt werden ca. 5 - 10 temporäre Vektorvariablen zu deklarieren und mich um die Freigabe etc. zukümmern.

Mal der Aufbau der Vektorenklasse
Delphi-Quellcode:
TVector2D = class
    constructor Create(); overload;
    constructor Create(_X, _Y: single); overload;
    constructor Create(AVec: TVector2D); overload;
  private
    FX, FY: single;

    function FGetdX: integer;
    function FGetdY: integer;
    function FGetLength: single;

    procedure FSetX(value: single);
    procedure FSetY(value: single);
    procedure FSetLength(value: single);
  public
    procedure Normalize(); overload;
    class function Normalize(AVector: TVector2D): TVector2D; overload;

    procedure Add(AVector: TVector2D); overload;
    class function Add(AVector: TVector2D; AnotherVector: TVector2D): TVector2D; overload;

    procedure Sub(AVector: TVector2D); overload;
    class function Sub(AVector: TVector2D; AnotherVector: TVector2D): TVector2D; overload;

    procedure Multiply(ASkalar: single); overload;
    class function Multiply(AVector: TVector2D; ASkalar: single): TVector2D; overload;

    procedure Divide(ASkalar: single); overload;
    class function Divide(AVector: TVector2D; ASkalar: single): TVector2D; overload;

    procedure FromWinkel(AWinkel: single; ALength: single);
    class function FromWinkelEx(AWinkel: single; ALength: single): TVector2D;

    function WinkelBetween(AVector: TVector2D): single; overload;
    class function WinkelBetween(AVector, AnotherVector: TVector2D): single; overload;

    class function Distance(AVector, AnotherVector: TVector2D): single;

    function Dot(AnotherVector: TVector2D): single; overload;
    class function Dot(AVector, AnotherVector: TVector2D): single; overload;

    property X: single read FX write FSetX;
    property Y: single read FY write FSetY;
    property dX: integer read FGetdX;
    property dY: integer read FGetdY;
    property Length: single read FGetLength write FSetLength;
  end;
Alle class function XYZ: TVector2D; geben eine neue Instanz eines Vektors zurück, was mir pro temporäre Zwischenrechnung die Initialisierung einer neuen Instanz erspart.

Momentan isses nun so, das ich wie gesagt tierisch auf die Freigabe der benutzten Temporären Vektoren achten muss.
Ma nen simples Beispiel.

Delphi-Quellcode:
procedure DoSomething(EinSpielelement, EinAnderesSpielelement: TEntity);
var
  tempVec: TVector2D;
begin
// Wir wollen die Distanz zwischen den beiden Spielelementen rauskriegen
// Dazu subtrahieren wir den Ortsvektor des einen Elementes vom anderen
// und ermitteln denn aus dem Vektor Ergebnis die Länge
// Ortsvektor wird bei TEntity unter "Pos" gespeichert
  tempVec := TVector2D.Sub(EinSpielelement.Pos, EinAnderesSpielelement.Pos);
  result := tempVec.Length;
  tempVec.Free();
end;
Wie gesagt, war das nun ein einfaches Beispiel und in der Regel brauch ich pro Methode 5 - 10 temporäre Vektoren um jeweils die Zwischenergebnisse abzuspeichern und dann freizugeben.

Ich würd das viel lieber so haben:

Delphi-Quellcode:
procedure DoSomething(EinSpielelement, EinAnderesSpielelement: TEntity);
var
  tempVec: TVector2D;
begin
  // SPEICHERLECK WEIL DIE INSTANZ VON TVECTOR2D NICHT WIEDER FREIGEGEBEN WIRD
  result := TVector2D.Sub(EinSpielelement.Pos, EinAnderesSpielelement.Pos).Length;
end;
Nur leider endet das dann im Speicherleck. Ich hab schon über eine Globale Liste aller Vektoren nachgedacht, wo ich nach jedem Spielezyklus alle ungenutzten Vektoren kille, nur leider müßte ich dann alle Nase lang mich drum kümmern um die Vektoren als "genutzt" zu kennzeichnen damit die Liste mir nicht versehentlicherweise nen genutzten Vektor freigibt und ich dann in die AVs rassel. Das setzen der Vektoren auf "gebraucht" würde aber eigentlich genauso viel Arbeit machen wie das freigeben, sprich ich wär nicht weiter.

Gibt es irgendwie in Delphi eine Möglichkeit automatisch ein Objekt killen zu lasen, sobald keine Referenz mehr drauf besteht wie z.b. in C# mit dem Garbage Collector ?

MfG

- Thebe
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#2

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 14:08
COM-Objekte machen sowas. Die haben Referenzzähler. Der Overhead ist zwar "relativ" gering, aber doch spürbar, insbesondere bei zeitkritischen Anwendungen.
Delphi-Quellcode:
Var
  x,y : IMyComInterface;

Begin
  x := GetObject; // object wird alloziiert. RefCount = 1
  x := Nil; // Referenz wird überschrieben, RefCount = 0==> Free
  
  x := GetObject; // object wird alloziiert. RefCount = 1
  y := x; // Refcount = 2
  x := Nil; // Referenz wird überschrieben, RefCount = 1
End; // Ende des Gültigkeitsbereichs von x und y. Delphi generiert den entsprechenden Code, um Speicherlecks zu vermeiden
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Thebe

Registriert seit: 25. Jul 2004
Ort: Wedel
78 Beiträge
 
Delphi 6 Enterprise
 
#3

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 14:27
Das hört sich doch schonmal klasse an..
Nur leider hab ich nicht wirklich Ahnung wie man das in meine Klasse einfädelt. Ich schätze mal das Funktioniert über Interfaces, nur von denen hab ich so gut wie null Ahnung. Kann man mir vielleicht nen Denkanstoß geben in wie fern das funktionieren soll ?
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#4

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 14:41
Prinzipiell ist das fast so wie eine Klasse. Schau mal unter TInterfaced Object. Sooo die Ahnung hab ich aber auch nicht.
geh mal zu sourceforge und saug dir das 'DWS', ein klasse Delphi-Interpreter!!! Deren Sourcecode ist voll mit Interface-Deklarationen. Als Nebeneffekt hast Du gleich mal soeben einen echt geilen Delphi-Interpreter!
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Marphy

Registriert seit: 24. Feb 2005
162 Beiträge
 
Delphi 7 Professional
 
#5

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 14:46
Hallo Thebe,
statt class functions solltest du vielleicht lieber Konstruktoren nutzen, aber das musst du selbst wissen.

Zu dem Problem selbst:
Nur um zwei Vektoren zu subtrahieren, brauchst du ja keine Klasse, da würde eine einfache Funktion voll und ganz genügen. Da es aber nur ein kleines Beispiel ist, kann ich das nicht so pauschal behaupten.

Ansonsten würde ich das vielleicht so machen:

1) Listenklasse implementieren oder TObjectList nutzen
2) Beim Beginn einer Routine, die Vektoren nutzt, wird die Klasse erstellt, bei deren Ende wieder zerstört.
3) Alle innerhalb der Routine genutzten Vektoren werden z.B. auf folgende Weise erstellt:
Delphi-Quellcode:
procedure MyProc();
var
  Lst: TMyListClass;
  V1,
  V2: TMyVectorClass;
begin
  Lst.Create();
  [...]
  V1 := Lst.Add();
  V2 := Lst.Add();
  [...]
  Lst.Free();
end;
4) Die Add-Methode erstellt jeweils eine neue Vektoren-Instanz, fügt sie der Liste hinzu und gibt sie zurück.
5) Durch Lst.Free() werden alle Objekte in der Liste freigegeben.

Ich hoffe, ich konnte dir wenigstens einen Denkanstoß geben

Gruß, Marco
Marco
Wo ein Wille ist, ist auch ein Weg. Aber wo ein Weg ist, ist nicht unbedingt auch ein Wille...
  Mit Zitat antworten Zitat
DerDan

Registriert seit: 15. Nov 2004
Ort: Donaueschingen
251 Beiträge
 
Delphi XE3 Professional
 
#6

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 15:28
Hallo


Ich würde auch eher mit nicht object orientierten functionen arbeiten um längen, winkel oder ähnliches zu ermitteln.

DerDan
nichts ist so schön wie man es sich vorstellt
  Mit Zitat antworten Zitat
Thebe

Registriert seit: 25. Jul 2004
Ort: Wedel
78 Beiträge
 
Delphi 6 Enterprise
 
#7

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 16:21
Soo
ich hab das nu ma mit den Interfaces probiert, nur so wirklich funkt das nicht.

Testklasse:

Delphi-Quellcode:
unit uTestClass;

interface

uses
  SysUtils;

  type
    TTestClass = class(TObject, IInterface)
    protected
      FRefCount: integer;
    
      function _AddRef: Integer; stdcall;
      function _Release: Integer; stdcall;
      function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    public
      class function NewInstance: TObject; override;
      property RefCount: Integer read FRefCount;
    end;

implementation

{ TTestClass }

function TTestClass._AddRef: Integer;
begin
  FRefCount := RefCount + 1;
  Result := FRefCount; // [X] HALTEPUNKT
end;

function TTestClass._Release: Integer;
begin
  FRefCount := FRefCount - 1;
  Result := FRefCount; // [X] HALTEPUNKT
  if Result = 0 then
    Destroy;
end;

function TTestClass.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

class function TTestClass.NewInstance: TObject;
begin
  Result := inherited NewInstance;
  TTestClass(Result).FRefCount := 1;
end;
Dazu wird an einer bestimmten Stelle folgender Code aufgerufen:

Delphi-Quellcode:
var
  t: TTestClass;
begin
  t := TTestClass.Create();
  t := nil;
end;
Tja, was soll ich sagen, weder _AddRef noch _Release werden aufgerufen. So funktioniert das schon mal auf alle Fälle nicht.

@Marphy:
Das Ding bei deinem Vorschlag ist ja, das erstma die Liste initialisiert werden muss. Dann muss ich ja auch noch alle Nase lang die temp. Variablen deklarieren um damit zu arbeiten. Wenn ich die nicht deklariere, dann komm ich ja nicht über das "MyList.Add()" hinaus. Danach muss ich dann auch noch mich zumindest um das Freigeben der Liste kümmern.
In etwa bin ich wieder bei +/- 0, ich muss weiterhin die Variablen deklarieren und ich muss weiterhin mich ums freigeben kümmern (auch wenn ein wenig einfacher nu). Ich finde, da lohnt sich das neuschreiben einer TVectorList Klasse noch nicht mal plus das umschreiben des bisherigen Codes für das Ergebnis.
Aber danke für den Denkanstoß!


MfG
- Thebe
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#8

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 17:17
Ich glaube du solltest eher das Singleton Pattern implementieren, wenn du einen Referenzzähler haben möchtest.
Das würde dann eher so aussehen :
Delphi-Quellcode:
unit UTestClass;

interface
 
uses ....;

  type
    TTestClass = class(TObject)
      protected
        refCount : Integer;
        constructor create;
      public
        class function getInstance : TTestClass;
        class procedure releaseInstance;
    end;

implementation

var GlobalInstance : TTestClass;

class function TTestClass.getInstance;
begin
  if not assigned(GlobalInstance) then
    begin
      GlobalInstance := TTestClass.create;
    end; // if assigned(GlobalInstance)
  inc(GlobalInstance.refCount);
  result := GlobalInstance;
end; // class function TTestClass.getInstance;

class procedure TTestClass.releaseInstance;
begin
  if assigned(GlobalInstance) then
    begin
      dec(GlobalInstance.refCount);
      if (GlobalInstance.refCount < 1) then
        begin
          GlobalInstance.Free;
        end; // if (GlobalInstance.refCount < 1)
    end; // if assigned(GlobalInstance)
end; // class procedure TTestClass.releaseInstance;

constructor TTestClass.create;
begin
  self.refCount := 0;
end; // constructor TTestClass.create;
Musst du gucken, ob du irgendwas nebenläufig machst, dann wäre natürlich ne Criticalsection nicht unwichtig. Für Fehler im Code vorab sorry, hab es gerade nur im Browser gemacht, ohne Syntaxcheck.
  Mit Zitat antworten Zitat
LarsMiddendorf

Registriert seit: 4. Sep 2003
Ort: Hemer
104 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: Freigabe eines Objektes wenn keine Referenz mehr drauf z

  Alt 30. Sep 2005, 17:20
Tja, was soll ich sagen, weder _AddRef noch _Release werden aufgerufen. So funktioniert das schon mal auf alle Fälle nicht.

Dafür muß die Variable als IInterface und nicht als TTestObject deklariert werden.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 09:01 Uhr.
Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf