Wiki Home

Test Memory Create Destroy


Namespace: WIN_COM_API
Here is the code for a benchmark I've been running for many years.-- Steven Black

It shows that, on a RAM basis, class RELATION is the lightest by far. In VFP6, the 5 lightest classes and the RAM required to create and hold 100 first-level subclasses are:

Relation 18388
NOTE: In VFP 7 SP1, and VFP8, Relation is no longer that small. In fact, Column now seems to be the smallest.
Column 50788
Dataenvironment 59584
Commandgroup 59588
Optiongroup 59588

NOTE: The new session class in VFP 6 SP3 doesn't even show in the top 5. For me it took just over 100K of ram.

-- Jim BoothOffsite link to http://www.jamesbooth.com
But it's 5 times smaller than Form, bless its little heart. -- Randy Pearson
Yes, but at 64k or so, Form Set remains the lightest datasession-bearing class, though with a limit in number of 255, something like that-- Steven Black
A formset has no limit itself. It's the form that is limited to 226 instances. But be carefull when using a formset for a private DS and the actual object that requires a private datasession is not the formset. With a SESSION object you can instantiate the session, issue SET DATASESSION TO and create another object that will then take over the private datasession. If you do the same with a formset you can encounter several data related problems, like VFP not updating indexes or being unable to detect conflict on a TABLEUPDATE() -- Christof Wollenhaupt
I'm not sure we're being fair to the SESSION class here. After all it does wonderful things, like defaulting to a private datasession. If I change the code below to add simply a DataSession=2 line to the Form Set class, the memory zooms up almost to the same as the Session (see code alteration below). When I then changed both classes to include an INIT function that opened a table in the private datasession, the memory usage of the two was almost idenitcal. Since nobody would use a Session object unless they wanted the private datasession, I think this needs to be taken into account. -- Randy Pearson
Yes, but what does this (memory test) realistically mean? We're talking Windows here, which caches things and mixes stuff up between RAM and Virtual Memory with other applications probably active. The problem with benchmarks in WinWorld is that nothing means nothing. -- John Koziol
Well, this is by no means a stress test, so there is surely no swapping going on. Furthermore I've run this test on every version of VFP since the first betas of 3.0 and the results have been consistent within versions, and the differences consistent among versions, regardless of the machines I've run this on. What this test measures is the time required to instantiate and destroy 100 objects that are 100 first-level subclasses, and the amount of RAM consumed according to VFP's admittedly dodgy memory functions. I would say that, in a relative context, the test is quite good at identifying and ranking classes, light vs heavy.
I'm surprised that Line doesn't make the list. In VFP3, wasn't that the lightest class? -- Barbara Peisch
From what I can tell, once you start adding properties (especially array props) - they even out pretty well - at least all the lighter ones -- Ken Matson
I believe relation's always been lightest, by a wide margin too... The line came up when I asked the VFP development team which was their lightest weight class. They answered line (unequivocally) but that's because Relation just didn't occur to them. It's one of those unseen classes...-- Steven Black

So, are we in agreement that RELATION is the lightest non-visual class and Line is the lightest visual class? What are the lightest visual and non-visual container classes? Also, what about custom? What does it have that makes it heavier than Line or Relation? Run the test :-). Your mileage may vary... -- Steven Black

I'm slightly confused here. I have a bunch of manager classes that are all based on Custom. Should I switch them to be based on Line (I'd like to keep it visual) ? If so, is there ever a case for using Custom if you don't need the private DS ? --PaulSmith
Yes - if you want to use the ADDOBJECT method, which custom has but line doesn't. -- Stuart Dunkeld
I added another class MyRelationSub2 to show that the relation takes up much more memory if you do not specify the name property. -- ChinBae
This size increase seems to only happen for the small non-visual classes with no name property, but it is definitly significant. In my case, relation went from 17568 to 60908 and column went from 49968 to 93304 just from commenting out the Name= line. In the visual classes, it actually reduces memory by a few bytes not to specify the name. It seems to be getting something that is about 43336 bytes added to it. A 42K penalty for not specifying a name seems quite steep. -- BradKarsjens

* These should ensure consistant results
#DEFINE DOSYS1104
#DEFINE ADDPROPERTYTEST
CLOSE ALL
RELE ALL EXTENDED

CLEAR ALL
CLEAR
PRIVATE lcOutFile
lcOutFile= [Test_memory_create_destroy_] + subs(version(),16,1) + [.TXT]
SET ALTERNATE TO &lcOutFile
SET ALTERNATE ON

? 'Source Generated by Speed.prg at 04/27/96 12:44:15 AM'
? 'Source: ', 'Test_memory_create_destroy.PRG', VERSION()
? 'Run Date: '+ TTOC( DATETIME())
#DEFINE cnNumObj  100
LOCAL i, lnTime1, lnTime2, lnTime3, nMem1, nMem2
lnTime1=SECONDS()
lnTime2=SECONDS()
lnTime3=SECONDS()
nMem1=INT(VAL(SYS(1016)))
nMem2=INT(VAL(SYS(1016)))
? 'Col 1: Number of Objects'
? 'Col 2: Object Class'
? 'Col 3: Memory required'
? 'Col 4: Seconds to create ' + ALLTRIM(STR(cnNumObj,5)) + ' objects'
? 'Col 5: Seconds to destroy '+ ALLTRIM(STR(cnNumObj,5)) + ' objects'
? 'Col 6: Tot time, Col(5)+Col(4)'

? PADR('Num',5), PADR('Class',20), PADL('Memory',10), ;
     PADL('Create',10), PADL('Destroy',10), PADL('Total',10)
? PADR('===',5), PADR('=====',20), PADL('======',10), ;
     PADL('======',10), PADL('=======',10), PADL('=====',10)
=LogFunc('MyCheckBoxSub1')
=LogFunc('MyColumnSub1')
=LogFunc('MyComboBoxSub1')
=LogFunc('MyCommandButtonSub1')
=LogFunc('MyCommandGroupSub1')
=LogFunc('MyContainerSub1')
=LogFunc('MyControlSub1')
=LogFunc('MyCursorSub1')
=LogFunc('MyCustomSub1')
=LogFunc('MyDataenvironmentSub1')
=LogFunc('MyEditBoxSub1')
=LogFunc('MyFormSub1')
=LogFunc('MyFormSetSub1')
=LogFunc('MyFormSetSub2')
=LogFunc('MyGridSub1')
=LogFunc('MyHeaderSub1')
=LogFunc('MyImageSub1')
=LogFunc('MyLabelSub1')
=LogFunc('MyLineSub1')
=LogFunc('MyListBoxSub1')
=LogFunc('MyOptionButtonSub1')
=LogFunc('MyOptionGroupSub1')
=LogFunc('MyPageSub1')
=LogFunc('MyPageFrameSub1')
=LogFunc('MyRelationSub1')
=LogFunc('MyRelationSub2')
=LogFunc('MySeparatorSub1')
=LogFunc('MySessionSub1')
=LogFunc('MyShapeSub1')
=LogFunc('MySpinnerSub1')
=LogFunc('MyTextBoxSub1')
=LogFunc('MyTimerSub1')
=LogFunc('MyToolBarSub1')
=EmptyTest('Empty')

********************************
FUNCTION LogFunc(tcClass)

#IFDEF DOSYS1104
	SYS(1104)
#ENDIF

WAIT WINDOW NOWAIT PADL(tcClass,20)
DIMENSION aBin[cnNumObj]
nMem1=INT(VAL(SYS(1016)))
lnTime1=SECONDS()
FOR i=1 TO cnNumObj
  aBin[i]=CREATE(tcClass)
ENDFOR
lnTime2=SECONDS()
nMem2=INT(VAL(SYS(1016)))
RELEASE aBin
lnTime3=SECONDS()
SET ALTERNATE TO  &lcOutFile ADDITIVE
SET ALTERNATE ON
? PADR(cnNumObj,5), PADR(tcClass,20), PADL(nMem2-nMem1,10), ;
     PADL(lnTime2-lnTime1,10), PADL(lnTime3-lnTime2,10), PADL(lnTime3-lnTime1,10)
SET ALTERNATE TO
SET ALTERNATE OFF

******************

FUNCTION EmptyTest(tcClass)
#IFDEF DOSYS1104
	SYS(1104)
#ENDIF
#IFDEF BINDEVENTTEST
	loObjectToBindTo = CreateObject("MycusHandler1")
#ENDIF
WAIT WINDOW NOWAIT PADL(tcClass,20)
DIMENSION aBin[cnNumObj]
nMem1=INT(VAL(SYS(1016)))
lnTime1=SECONDS()
FOR i=1 TO cnNumObj
  aBin[i]=CREATE(tcClass)
  #IFDEF ADDPROPERTYTEST
    AddProperty(aBin[i],"Prop1")
  #ENDIF
ENDFOR
lnTime2=SECONDS()
nMem2=INT(VAL(SYS(1016)))
RELEASE aBin
lnTime3=SECONDS()
SET ALTERNATE TO &lcOutFile ADDITIVE
SET ALTERNATE ON
? PADR(cnNumObj,5), PADR(tcClass,20), PADL(nMem2-nMem1,10), ;
     PADL(lnTime2-lnTime1,10), PADL(lnTime3-lnTime2,10), PADL(lnTime3-lnTime1,10)
SET ALTERNATE TO
SET ALTERNATE OFF
ENDFUNC

*****************

DEFINE CLASS MyCheckBoxSub1 AS CheckBox
  Name= 'MyCheckBoxSub1'
ENDDEFINE

DEFINE CLASS MyColumnSub1 AS Column
  Name= 'MyColumnSub1'
ENDDEFINE

DEFINE CLASS MyComboBoxSub1 AS ComboBox
  Name= 'MyComboBoxSub1'
ENDDEFINE

DEFINE CLASS MyCommandButtonSub1 AS CommandButton
  Name= 'MyCommandButtonSub1'
ENDDEFINE

DEFINE CLASS MyCommandGroupSub1 AS CommandGroup
  Name= 'MyCommandGroupSub1'
ENDDEFINE

DEFINE CLASS MyContainerSub1 AS Container
  Name= 'MyContainerSub1'
ENDDEFINE

DEFINE CLASS MyControlSub1 AS Control
  Name= 'MyControlSub1'
ENDDEFINE

DEFINE CLASS MyCursorSub1 AS Cursor
  Name= 'MyCursorSub1'
ENDDEFINE

DEFINE CLASS MyCustomSub1 AS Custom
  Name= 'MyCustomSub1'
ENDDEFINE

DEFINE CLASS MyDataenvironmentSub1 AS Dataenvironment
  Name= 'MyDataenvironmentSub1'
ENDDEFINE

DEFINE CLASS MyEditBoxSub1 AS EditBox
  Name= 'MyEditBoxSub1'
ENDDEFINE

DEFINE CLASS MyFormSub1 AS Form
  Name= 'MyFormSub1'
ENDDEFINE

DEFINE CLASS MyFormSetSub1 AS FormSet
  Name= 'MyFormSetSub1'
ENDDEFINE

DEFINE CLASS MyFormSetSub2 AS FormSet && FormSet with Private Datasession
  Name= 'MyFormSetSub2'
  DataSession = 2
ENDDEFINE

DEFINE CLASS MyGridSub1 AS Grid
  Name= 'MyGridSub1'
ENDDEFINE

DEFINE CLASS MyHeaderSub1 AS Header
  Name= 'MyHeaderSub1'
ENDDEFINE

DEFINE CLASS MyImageSub1 AS Image
  Name= 'MyImageSub1'
ENDDEFINE

DEFINE CLASS MyLabelSub1 AS Label
  Name= 'MyLabelSub1'
ENDDEFINE

DEFINE CLASS MyLineSub1 AS Line
  Name= 'MyLineSub1'
ENDDEFINE

DEFINE CLASS MyListBoxSub1 AS ListBox
  Name= 'MyListBoxSub1'
ENDDEFINE

DEFINE CLASS MyOptionButtonSub1 AS OptionButton
  Name= 'MyOptionButtonSub1'
ENDDEFINE

DEFINE CLASS MyOptionGroupSub1 AS OptionGroup
  Name= 'MyOptionGroupSub1'
ENDDEFINE

DEFINE CLASS MyPageSub1 AS Page
  Name= 'MyPageSub1'
ENDDEFINE

DEFINE CLASS MyPageFrameSub1 AS PageFrame
  Name= 'MyPageFrameSub1'
ENDDEFINE

DEFINE CLASS MyRelationSub1 AS Relation
  Name= 'MyRelationSub1'
ENDDEFINE

DEFINE CLASS MyRelationSub2 AS Relation
&&Omit the name and it becomes much fatter
&&Not in VFP 7/8!
ENDDEFINE

DEFINE CLASS MySeparatorSub1 AS Separator
  Name= 'MySeparatorSub1'
ENDDEFINE

DEFINE CLASS MySessionSub1 AS Session
  Name= 'MySessionSub1'
ENDDEFINE

DEFINE CLASS MyShapeSub1 AS Shape
  Name= 'MyShapeSub1'
ENDDEFINE

DEFINE CLASS MySpinnerSub1 AS Spinner
  Name= 'MySpinnerSub1'
ENDDEFINE

DEFINE CLASS MyTextBoxSub1 AS TextBox
  Name= 'MyTextBoxSub1'
ENDDEFINE

DEFINE CLASS MyTimerSub1 AS Timer
  Name= 'MyTimerSub1'
ENDDEFINE

DEFINE CLASS MyToolBarSub1 AS ToolBar
  Name= 'MyToolBarSub1'
ENDDEFINE


This is a cool test -- Jean Denis
I would like to see the VFP 8 EMPTY class added to the test, perhaps a factory function that generates an EMPTY object and adds 2 properties. - Albert Ballinger
Sounds good to me!! Updated to include a test for EMPTY... didn't do too well.
I added the new VFP8|9 Collection class to the test code and ran it. The results were interesting.

Results sorted by Memory size:
Count	Class Name	 Bytes for 1000 Instances
------	---------------	 ------------------------
1000	Column	         344,624
1000	Timer	         440,640
1000	Relation 2	 448,412
1000	Shape	         452,640
1000	Relation 1	 452,644
1000	Line	         452,644
1000	Custom	         456,552
1000	Image	         456,552
1000	Empty	         472,092
1000	Separator	 476,488
1000	Form Set 1	 476,496
1000	Page	         480,508
1000	Header	         481,072
1000	Container	 504,568
1000	Control	         504,576
1000	Cursor	         528,552
1000	Label	         532,620
1000	Data Environment 552,528
1000	Session	         664,624
1000	Command Group	 688,620
1000	Option Group	 688,620
1000	Check Box	 780,292
1000	Page Frame	 868,560
1000	Tool Bar	 992,496
1000	Form Set 2	 1,060,616
1000	Collection	 1,072,640
1000	Option Button	 1,128,644
1000	Command Button	 1,144,528
1000	List Box	 1,472,624
1000	Form	         1,705,084
1000	Edit Box	 2,780,464
1000	Test Box	 2,784,512
1000	Grid	         3,036,500
1000	Spinner	         4,588,464
1000	Combo Box	 5,704,448


I have read and heard people say in the past how the Line class is the lightest in memory weight. According to this test, the Line class is one of the lightest, but not THE lightest. I find it interesting how the Custom class is actually not much "heavier". However, there is a dramatic difference in total time to create and destroy 1,000 objects of each class.

Count	Class Name	 	Total Create|Destroy for Each
------	----------------	-----------------------------
1000	Cursor	 		0.0000090
1000	Custom	 		0.0000110
1000	Timer	 		0.0000180
1000	Collection	 	0.0000180
1000	Relation 1	 	0.0000190
1000	Empty	 		0.0000200
1000	Relation 2	 	0.0000220
1000	Column	 		0.0000230
1000	Control	 		0.0000230
1000	Data Environment	0.0000230
1000	Container	 	0.0000250
1000	Shape	 		0.0000260
1000	Separator	 	0.0000260
1000	Form Set 1	 	0.0000260
1000	Page	 		0.0000260
1000	Image	 		0.0000270
1000	Line	 		0.0000280
1000	Check Box	 	0.0000290
1000	Command Group	 	0.0000340
1000	Page Frame	 	0.0000350
1000	Label	 		0.0000380
1000	Header	 		0.0000440
1000	Command Button	 	0.0000440
1000	Edit Box	 	0.0000530
1000	Option Group	 	0.0000550
1000	Session	 		0.0000560
1000	Option Button	 	0.0000620
1000	Form Set 2	 	0.0000710
1000	Grid	 		0.0000980
1000	Test Box	 	0.0001240
1000	List Box	 	0.0002790
1000	Spinner	 		0.0003310
1000	Combo Box	 	0.0013070
1000	Tool Bar	 	0.0099880
1000	Form	 		0.0103150


Note how the total time to create and destroy a Line class is about 1 1/2 times more than what it takes to create a Custom class. So, if I am considering using some class as a Business tier object and have to choose memory over time, I will choose time. Choosing time means, I will opt for using the Custom class as my basis for Business tier class objects rather than the line. The memory requirement per instance only costs me 4 bytes of memory (Custom = 457 Bytes Vs. Line at 453).

Category Performance Category Code Samples
( Topic last updated: 2006.04.19 10:39:00 AM )