Zoek

Uitgebreid zoeken Artikelen per auteur

  

Undocumented Visual Objects (part 1)

De meeste Visual Objects (VO) leden van de SDGN zal het niet ontgaan zijn, maar voor diegenen die de laatste maanden geen nieuwsgroepen hebben gevolgd: sinds begin van dit jaar maakt ondergetekende deel uit van het VO ontwikkelteam van GrafX software. Dit is aanleiding geweest voor Ed Richard om mij te vragen een column te schrijven voor de SDGN site waarin ik jullie kan vermaken/informeren over niet/slecht gedocumenteerde zaken en nieuwtjes/weetjes over VO. Na enig aarzelen heb ik daarin toegestemd, en het gevolg kunnen jullie lezen.

Deze keer wil ik het hebben over het dynamisch geheugen van VO , en dat zal zeker niet de laatste keer zijn dat ik het daarover zal hebben. Zoals bekend is VO in tegenstelling tot talen als Delphi en C/C++ uitgerust met een dynamisch geheugen. Dat houdt in dat je als ontwikkelaar niet al te veel zorgen hoeft te maken over het toekennen en vrijgeven van geheugen voor Strings, Objecten, Arrays enz. In de regel werkt het allemaal probleemloos, maar in enkele uitzonderlijke situaties kan het nodig zijn, dat je als ontwikkelaar VO een handje helpt bij het opruimen van zaken. Een voorbeeld is de situatie waarbij je objecten hebt die onderling naar elkaar verwijzen, zoals in onderstaande figuur:

De situatie die hierboven staat, daar komt de Garbage Collector (GC) wel uit, maar het kan nog verschrikkelijk veel ingewikkelder wordn, en dan kan het zijn dat de GC er echt niet meer uitkomt. In die situaties kun je de GC een handje helpen door je klassen te voorzien van een destroy methode waarin de onderlinge verwijzingen worden opgeruimd.

Method Destroy() Class oA
Self:oB:Destroy()
Self:oB := NULL_OBJECT

Method Destroy() Class oB
Self:oA:Destroy()
Self:oA := NULL_OBJECT


Als je dan in je code het object opruimt door de Destroy() methode handmatig aan te roepen, verbreek je de onderlinge relatie en wordt het voor de Garbage Collector eenvoudiger te onderzoeken welke objecten opgeruimd kunnen worden.

Als je dat niet doet, zou het zo kunnen zijn dat er dynamische objecten blijven hangen. Wanneer je nu op een gegeven moment in je programma zou willen weten welke dynamische variabelen er zoal in je programma-geheugen aanwezig zijn, dan kun je gebruik maken van de volgende (niet gedocumenteerde) runtime functie:

DynStack2Array()

Neem bv. het VO standaard framework. Als je daar onderaan de StdDataWindow StandardDataWindow:Init() methode de onderstaande volgende code toevoegt, dan kun je zien welke dynamische variabelen er op het moment van het openen van een datawindow in het geheugen staan.

METHOD Init(……………) CLASS StdDataWindow
  .
  .
  SELF:PostInit()

METHOD PostInit() CLASS StdDataWindow
  LOCAL i AS DWORD
  LOCAL aStack AS ARRAY
  SetAlternate(TRUE,"c:\info.txt")
  aStack := DynStack2Array()
  ? aLen(aStack)
  FOR i := 1 TO aLen(aStack)
    IF ISObject(aStack[i])
      ? "Object ", Classname(aStack[i]), aStack[i]
     ELSEIF IsArray(aStack[i])
      ? "Array ", Alen(aStack[i])
     ELSEIF IsString(aStack[i])
      ? "String ", aStack[i]
     ELSEIF IsFloat(aStack[i])
      ? "Float  ", aStack[i]
     ELSE
      ? "????   ", aStack[i]
    ENDIF
  NEXT
  SetAlternate(FALSE)

Open vervolgens een DBF bestand via het menu File/Open. Dan zul je ongeveer de volgende uitvoer krijgen.

50
Object  STANDARDSHELLWINDOW {(0x00F8)0x01861808} CLASS STANDARDSHELLWINDOW
Object  APP {(0x0034)0x01861448} CLASS APP
Object  APP {(0x0034)0x01861448} CLASS APP
Object  TOOLBAR #TOOLBAR:
Object  EVENT {(0x001C)0x0186900C} CLASS EVENT
Object  EVENT {(0x001C)0x0186900C} CLASS EVENT
.
.
.
String  .DBF
String  .dbf
String  D:\Cavo26\SAMPLES\Gstutor\Customer.dbf
String  D:\Cavo26\SAMPLES\Gstutor\Customer.dbf
Object  STANDARDSHELLWINDOW {(0x00F8)0x018617AC} CLASS STANDARDSHELLWINDOW
String  Browse Database: D:\Cavo26\SAMPLES\Gstutor\Customer.dbf
Object  DBSERVER Customer
String  D:\Cavo26\SAMPLES\Gstutor\Customer.dbf
Object  STANDARDSHELLWINDOW {(0x00F8)0x018617AC} CLASS STANDARDSHELLWINDOW
Object  STDDATAWINDOW {(0x0164)0x01861640} CLASS STDDATAWINDOW
String  c:\info.txt
Object  STDDATAWINDOW {(0x0164)0x01861640} CLASS STDDATAWINDOW

Je ziet: er zijn op dat moment al zo’n 50 verwijzingen naar Dynamic memory in je applicatie. Sommige verwijzingen wijzen naar hetzelfde object, dus het totaal geheugengebruik is geringer. Je ziet in die array ook alle strings die op dat moment door VO zijn aangemaakt. Open je de DBF via de toets Ctrl-O, dan is de array kleiner, omdat er dan een andere weg door het programma wordt afgelegd.

De DynStack2Array() functie kan handig zijn als je op een bepaald moment in je applicatie wilt weten welke dynamische variabelen door VO zijn aangemaakt, en een bepaalde variabele zou willen opruimen. Je kunt hem zien als een vervanger van c.q. aanvulling op de CreateGCDump() die wel gedocumenteerd is. Realiseer je echter dat DynStack2Array() zelf ook een dynamische variabele (een array) aanmaakt. Als je in bovenstaande code de regel:

aStack := DynStack2Array()

2 keer aanroept:

aStack := DynStack2Array()
aStack := DynStack2Array()

dan zul je zien dat de tweede array 1 element groter wordt en dat er onderaan de lijst een Array is toegevoegd.

Ik hoop dat jullie hier iets aan hebben.

Tenslotte dit: tijdens de laatste CttP heb ik het al aan de aanwezigen gezegd: Brian Feldman van GrafX (mijn baas binnen het team) heeft tijdens DevFest in London aan de aanwezigen gevraagd de top 5 aan wensen voor VO 2.7 aan hem te mailen (bugshunter@cavo.com). Aarzel niet en stuur hem je wensen.

Robert van der Hulst

Geef feedback:

CAPTCHA image
Vul de bovenstaande code hieronder in
Verzend Commentaar