John W. Colby
jwcolby at colbyconsulting.com
Tue Mar 16 12:34:47 CST 2004
I have had a lot of people worry, if you will, about loading hundreds of instances of various classes. What does this do in terms of memory? How does Access (VBA) handle the loading of this stuff? If I have a thousand lines of code in a text box class and load 100 text box classes, do I have 100,000 lines of code loads? What about variables? If a class loads, when the second instance loads is it using the same variables? What about static variables in procedures? In order to answer the "performance" issue perhaps it would be useful to talk about how classes do what they do. We are told, and I have no way to test it myself to find out, but we are told, that in a library an entire module loads at once. If you call a function in a library, every function in that module is loaded into memory. There is a lot of discussion about breaking modules down into tightly related functions so that we aren't loading a lot of code that isn't needed because we call only one function. I have already discussed my take on the matter, if I load the whole darned thing, my 5mbytes will be small potatoes to the footprint of my application, Access, Outlook, Word and Windows. But if you truly need something to worry about, you are of course welcomed to break your modules down into tiny little things so that only the exact functions you need get loaded. As for classes, by definition since I am loading a piece of that class, the whole banana is going to load. After that however when the second instance loads no more CODE loads, just like a second instance of any method in a regular module doesn't load over and over. When a function loads, a STACK is created onto which the arguments being passed in are placed. Also placed into that stack are the variables internal to the function, WITH THE EXCEPTION OF static variables. Static variables are placed on the HEAP which is a global area of memory allocated to the application by Windows. Variables declared in the header of ANY MODULE, class or otherwise are placed on the heap. What this means is that, for example, my class has a single Long Integer declared in the class header. As the class loads, ALL OF THE CODE loads, then memory is allocated by Access (VBA Actually) for that Long Integer on the heap. When I load a second instance of the class, I add exactly and ONLY one more Long Integer to the heap. No more code is loaded. Of course this isn't exactly true since in order to load that instance I have to declare a variable somewhere to hold a pointer to the class itself, but the concept remains that only the pointer to the class and the data in the header of the second instance of the class is actually "overhead" of that instance. So if I load a dclsFrm, all the code loads and all of the variables for that form. Load a second form and only the data for that second dclsFrm instance loads. Load 45 dclsCtlCbo instances and all of the code in dclsCtlCbo loads plus any variables in the header, after which 44 "headers" are loaded (the variables for 44 other instances). As you can see, once you load one, the overhead for the next 10 or 1000 is negligible - at least in terms of additional code and heap space. There may or may not be other "overhead" such as recordsets opened and data loaded into collections etc. That is indeed an issue, it is very real overhead, and it can't be discounted. We as class designers need to be aware of how this stuff works, what is and isn't loaded for each instance of any given class, and how that might influence performance. I do a lot of stuff with collections. I load a SysVar class which loads off of disk dozens of SysVars into collections. Yes, that is real overhead for that class, and I can calculate roughly how much memory is used and how long it takes to get the data off the disk and into the collection. Having done that however, it sits there in memory until the application closes. My app runs faster because I used a few thousand bytes of memory to just load the SysVars instead of getting them off the disk every time I want to know the value of the SysVar. I do not intend to make light of the overhead of class programming. If you are attempting to squeeze this stuff into a Win98 box with 32 megs of memory, a framework probably isn't the way to proceed. On the other hand if you are developing an app for a small company with 5 computers, the development time a Framework can save you, and the difference in your bill to the client, just might buy the client all new hardware. Which would the client prefer? New 2ghz machines costing $1,000 apiece or a bill of an additional $5000 for your time? Frameworks can save a LOT of programming effort in many cases. There are those out there who have never tried them, can't really get a handle on how they work, and will just dismiss them as "can't possibly help me". There are others who have already built their own and know what I am talking about. And yes, there may be one or two who truly don't do things that a framework would be useful for. I can't say I've ever met anyone ... ;-) John W. Colby www.ColbyConsulting.com