Seite 1 von 2

Object destroyen

Verfasst: Mi, 14. Nov 2012 10:31
von Manfred
Hi,

wenn ich ein Objekt einer eigenen Klasse destroyen will, dann genügt es ja nicht das Objekt selbst auf NIL zu setzen. Es muß eine eigene destroy() Methode her. Das bedeutet doch, dass diese Destroy() Methode alle Memvars NILLEN muß. Was mache ich aber, wenn das etliche sind? Muß ich die alle einzeln angeben, oder könnte man sowas in einer Superklasse unterbringen, die dann mit entsprechenden Prüfungen alle Mebervars ermittelt und dann auf NIL setzt? Ich habe jetzt auf Anhieb nichts in der Anleitung gefunden, was mir da weiterhelfen könnte.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 10:44
von brandelh
Hallo Manfred,

wegen eigenen Xbase++ Variablen (local, private) brauchst du kein destroy(), das macht der GC selbstständig.
Wenn du große Strings gespeichert hast, kannst du helfen indem du die auf NIL setzt.

destroy() braucht man nur wenn in create() Systemresourcen (Drucker, Fonts etc.) angefordert wurden.
Diese Systemresourcen würden sonst im Speicher bleiben und nur die Brücken dahin (Xbase++ Variablen) abgebrochen.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 10:44
von Jan
Wie allgemein bekannt bin ich ja kein Klassenmensch. Aber vielleicht ist das doch ein Denkansatz: Wenn ich gesammelt eine Gruppe von Objekten destroy()en möchte, dann mach ich das über oParent:childList(). Das zurückgegebene Array kann ich dann Position für Position abarbeiten. Manchmal destroy()e ich alle Children, manchmal nur die, die einem entsprechenden XBPart entsprechen. Was man ja ebenfalls abfragen kann.

Jan

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 10:46
von Manfred
Hallo Hubert,

ich denke da in erster Linie an meinen Thread mit den GDI Objekten. Da hat der GC total versagt.

@Jan,

ich glaube Du hast da wieder was in den falschen Hals gekriegt.. :lol:

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 10:59
von Jan
Manfred,

mag sein. Aber da Du im Eingangsbeitrag nicht exakt beschrieben hast, welche Arten von Objekten Du destroy()en willst, kam mir der Gedanke, das über den Parent-Weg versuchen zu können. Eventuell in Deinem Klassen-Denken mit anderen Methoden, aber vom Ansatz her ähnlich.

Jan

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:01
von Tom
Ein Klassenobjekt, das irgendwo erzeugt wird, ist eine ganz normale Variable - und wird auch wie eine solche behandelt. Erzeuge ich das Klassenobjekt als LOCAL, verschwindet es am Ende der Funktion, dito bei PRIVATEs. Ich muss nix "nilen", erst recht nicht iVars oder so - das wäre auch hanebüchen. Ein Destroy() muss nur bei XbParts und davon abgeleiteten Objekten erfolgen, außerdem bei AutomationObjects. Dort erbt man aber die implizite Methode, so dass das automatisch passiert, wenn beispielsweise der Parent am Ende eines Dialogs zerstört wird. Man kann sie in solchen Fällen aber auch gezielt auslösen, wenn man auf Nummer sicher gehen will.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:09
von Manfred
OK,

anders herum. In dem Thread über GDI Objekte ist klar geworden, das es Fälle gibt, in denen der GC total überfordert ist. Nachdem ich nun alles mögliche was ich finden konnte genillt hatte, sah die Sache schon wesentlich besser aus. Jetzt hatten wir gestern das Thema in Leverkusen und da kam der Hinweis, dass es nicht genügt, wenn ich meine eigenen Objekte einfach nur nille. Ich müßte da schon ein destroy einbringen, welches alle Membervars nillt usw., damit die im Objekt enthaltenen Membervars nicht irgendwo im Nirwana herumschwirren. Da es aber nicht vorhanden ist in den eigenen Klassen, muß diese Methode nachprogrammiert werden. Soweit so gut. Nun dachte ich dass man sowas pauschalisieren könnte, aber dem ist wohl nicht so.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:18
von brandelh
Hallo Manfred,

lies doch mal die Beschreibung von NEW()/INIT(), CREATE() und DESTROY() nach.
NEW()/INIT() erzeugen die Xbase++ Variablen. Um die kümmert sich der GC normalerweise völlig selbständig.
CREATE() fordert nun vom Betriebssystem für XbpParts (Dialogfenster, Buttons, Fonts, Drucker, etc.) (GDI)-Resourcen an, falls du diese verwendest.
Wenn du solche verwendest, musst du diese auch in einer Methode DESTROY() wieder freigeben.
Wenn du Dateien öffnest, musst du diese ja auch wieder schließen.
Wenn du aber nur Arrays, Strings etc. hast, dann werden die automatisch aufgeräumt.

Es gibt aber Programme, die laden so nebenbei 200 MB in Stringvariablen und rufen die Funktion auch noch dauernd auf.
Hier KANN es dazu kommen, dass der GC nicht nachkommt und Probleme entstehen, die man beseitigen kann wenn man die riesigen Stringvars auf NIL setzt.
Man muss nicht, aber es hilft dem GC ;-)

Ansonsten ist es natürlich IMMER empfehlenswert für eigene Klassen ein DESTROY() zu definieren, auch wenn man nichts drinn macht.
So weiß der Anwender, dass man daran gedacht hat ;-)

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:25
von Manfred
Also irgendwie kommen wir nicht zu Kern der Sache.

Es ist vollkommen uninteressant, ob es notwendig ist oder nicht. Ich wollte nur wissen, ob sowas geht.

Allerdings könnte vielleicht hier schon direkt ein Abschluß getroffen werden: Wenn ich z.B. ein LOCAL Objekt aus einer eigenen Klasse erzeuge mit x iVars und dieses Objekt dann vor dem Verlassen der Funktion z.B. nur dieses Objekt auf NIL setze, wird dann alles was darin ist auch genillt, oder besteht die Gefahr, dss dann "Speichermüll" übrigbleibt. Vollkommen egal, ob es den GC gibt oder nicht. es geht nur um die reine Theorie. Deshalb habe ich mir die Gedanken dazu gemacht. Wenn alles andere auch genillt wird, dann hat sich meine Frage erübrigt.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:33
von Tom
Destroy() gibt die Systemressourcen eines GDI-Objekts/XbParts wieder frei. Diese Methode macht überhaupt nichts mit den Instanzvariablen des Objekts; Du kannst es im vorigen Zustand restaurieren, einfach durch ein abermaliges Create(). Das hat mit Speicherauslastung o.ä. wenig zu tun. Destroy() verhindert lediglich, dass ein GDI-Objekt referenziert bleibt (nebst Children), das längst inaktiv ist. Wenn man ein solches Klassenobjekt löschen will, indem man ihm z.B. NIL zuweist, sollte es vorher zerstört werden.

Ein Objekt ist ansonsten mit einem Array zu vergleichen. Wenn ich a := {} mache oder aSize(a,0), werden - natürlich - auch alle Arrayelemente gelöscht. Genau dasselbe geschieht mit einem Objekt: Die Löschung des Objekts selbst führt selbstverständlich auch zur Löschung aller Instanzvariablen. Sonst wäre das ja haarsträubende Arbeit und eine originelle Version von OOP. Es dürfte auch schwer werden, die Instanzvariablen eines Objekts zu "nilen", das man selbst vorher insgesamt auf NIL gesetzt hat - schließlich existiert die Objektreferenz in diesem Augenblick nicht mehr. Das wäre auch der Fall, wenn man der Objektvariablen beispielsweise einfach einen numerischen Wert zuweisen würde. Ist unterm Strich dasselbe.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:37
von Manfred
naja,

das man zuerst im Objekt selbst aufräumen muß und danach erst das Objekt nillt, dass ist mir schon klar. Deshalb habe ich es auch nicht ausdrücklich erwähnt. Und das andere ist mir auch klar. :roll: Also vorher destroy() und dann NIL

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:42
von UliTs
Das Problem ist, dass LOCALs von Funktionen eben nicht immer vom Garbage Collector freigegeben werden können, wenn der Funktionsaufruf beendet wird!
Beispiel:

Code: Alles auswählen

FUNCTION GibMirEinenBloedenCodeBlock()
LOCAL A,B,C,D
  A := 10
  B := 20
  C := 30
  D := array( 100000 )
RETURN( {||A+B+C} )
In diesem Fall können die LOCALs A,B,C NICHT freigegeben werden, da sie ja im Codeblock verwendet werden!
Wenn so etwas vorkommt, werden meines Erachtens gleich ALLE LOCALs nicht freigegeben, also auch nicht D !
Und wenn diese Funktion ein paar 100000 mal aufgerufen wird, müßte es irgendwann knallen :happy10: :tongue2: :toothy3: :triplets:

Uli

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:44
von Manfred
Ja,

das ist auch der letzte Rest, der noch übrigbleibt bei mir und für den ich keinen Ersatz wüßte. Darüber habe ich auch schon gegrübelt. :evil:

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:47
von UliTs
Hast Du ein möglichst kurzes Beispiel, wo Du keine Idee für einen Ersatz hast?

Uli

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:51
von Manfred
z.B. diese simple Funktion, die ein False oder True zurückliefert. lErfolg kann ich ja nicht vorher nillen.....

Code: Alles auswählen

Function test()
             local lerfolg := .T.
             if nicht
                lerfolg := .F.
             endif
             return lErfolg

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:53
von UliTs
Da brauchst Du auch nichts zu "nilen", da in Deinem Beispiel der Garbage-Collector "weiß", dass er alle LOCALs freigeben kann ...
Uli

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 11:53
von brandelh
Hallo Uli,

bist du dir bei deinem Beispiel sicher ?
Ich denke, dass D immer freigegeben wird, da auf D keine externen Verweise liegen.
Wie kann man das übrigens nachprüfen ?

Hallo Manfred,

bei deiner Funktion erübrigt sich jeder Gedanke ;-)
Als Ergebnis wird der WERT .t. oder .f. zurückgeliefert, die Variable lErfolg wird sauber entsorgt.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:01
von brandelh

Code: Alles auswählen

function MyUpper( cTxt ) // cTxt erhält eine Kopie des übergebenen Wertes und wird LOCAL
    local cX := upper(cTxt) 
return cX        
cAltText := "abc"
cNeuText := MyUpper( cAltText )

Hier ist die Zuordnung nicht ganz so eindeutig. cX ist zwar LOCAL und wird als solche auch entsorgt, ist aber tatsächlich ja nur ein Zeiger auf den ASCIIZ String, der zugewiesen wurde.
Der Rückgabewert ist intern ein Pointer auf den tatsächlichen Text. cX wird also sauber entsorgt (der Pointer), der Text bleibt aber unter dem neuen Pointer (cNeuText) weiter erreichbar (wäre auch blöd wenn nicht ;-) ) ...

Aus diesem Grunde ist es sinnvoll nicht benötigte RIESIGE Texte mit "" oder NIL zurückzusetzen.
Der GC kann diese dann schneller freigeben. Das hat aber alles nichts mit den obenen genannten Resourcen zu tun, da hat Tom schon recht.

Sobald die EXE beendet wird, wird von der Runtime schon dafür gesorgt, dass alles (Speicher und Resourcen) wieder freigegeben werden.
Daher ist das Ganze auch nur wichtig, wenn die Funktion sehr oft aufgerufen wird bzw. das Programm im 24/7 Betrieb laufen soll.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:06
von Wolfgang Ciriack
Hallo Manfred,
wenn du trotzdem irgendetwas mit den Vars anfangen willst, könntest du vielleicht das nutzen:

Code: Alles auswählen

aVars:=obj:classDescribe(CLASS_DESCR_MEMBERS)
l:=len(aVars)
for i:=1 to l
     xName:=aVars[i, CLASS_MEMBER_NAME]
     xVal :=obj:&( aVars[i, CLASS_MEMBER_NAME] )
..........

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:07
von Manfred
Ja,

es werden alle Variablen entsorgt. Vom GC halt. Aaaber, was ist wenn sowas andauernd gemacht wird? Kommt der GC da noch mit auf die Dauer? Das Grundkonzept mit dem GC klappt ja auch. Nur nicht, wenn er stark gefordert wird. [-X

Ah Hubert hat noch einen nachgelegt, aber mit seinem letzten Satz genau ins Schwarze getroffen. Das ist das was ich als Problem hatte. Ich habe es jetzt allerdings ganz anders gelöst. Das Programm hat eh einen geplanten Tageswechsel, an dem was passiert und da rufe ich das Programm neu auf und beende das aktuelle. Mal sehen ob das eine Lösung ist mit der man leben kann.

Grr, Wolfgang kam auch noch dazwischen.

Das hatte ich auch mal kurz gelesen, aber so verstanden, dass das alles nur für dynamische Klassen gelten sollte.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:12
von Manfred
Hi Wolfgang,

das werde ich mir mal näher ansehen. Wenn das damit klappt, wäre es genau das was ich suchen würde. Das hatte ich doch total übersehen. ich war woanders drin was auch Class hieß.

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:17
von UliTs
brandelh hat geschrieben:Hallo Uli,

bist du dir bei deinem Beispiel sicher ?
Ich denke, dass D immer freigegeben wird, da auf D keine externen Verweise liegen.
Wie kann man das übrigens nachprüfen ?
Ich bin mir ziemlich sicher, dass der Garbage Collector das zwar theoretisch könnte, praktisch aber nicht kann (=entsprechend intelligent programmiert ist) :-) :-( .
Ich meine, dass hatte Steffen mal selbst gesagt!
-
Von Dir so eine Frage: "Wie kann man das nachprüfen"? 8)
Ich würde sagen, ein Testprogramm schreiben :) Mir fehlt aber im Moment die Zeit, aber Du .....?
Uli

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:28
von Tom
cX ist zwar LOCAL und wird als solche auch entsorgt, ist aber tatsächlich ja nur ein Zeiger auf den ASCIIZ String, der zugewiesen wurde.
Wer erzählt denn so was?

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:53
von Tom
Ich erinnere mich, dass SP beim Forentreffen oder bei der DevCon zugesagt hatte, Alaska wolle gelegentlich ins Forum schauen, um dann via Verein bei Threads zu intervenieren (also eine Klarstellung zu liefern), die inhaltlich aus dem Ruder laufen. Ich denke, dieser Thread wäre eine gute Gelegenheit, um diese Vorgehensweise mal auszuprobieren. :badgrin:

Re: Object destroyen

Verfasst: Mi, 14. Nov 2012 12:56
von Manfred
habe ich indirekt schon angeleiert....