19

I've found myself having to write some VBA code recently and just wondered if anyone had ever come across any details on how the VBA garbage collector works? The .Net GC is very well-documented indeed but I can't find a single shred of detail on the VBA GC, other than that vague mentions that it's a reference counter. I assume that it's pretty similar to the VB6 GC but can't find any information on that either.

Specifically, I'd be interested in knowing:

  • What triggers a GC
  • What algorithm it uses (is collection generational, for example?)
  • How (if at all) does it handle circular references?
  • Is there any way of monitoring its operation

This is more out of curiosity than any particular need to know, any insight at all much appreciated!

Jon Artus
  • 6,268
  • 11
  • 42
  • 41
  • 3
    Konrad's answer is all you need, but I'll also point you to the VB Programmer's Guide, specifically the section on "Object Models", which discusses reference counting, "tearDown methods", and the like: http://msdn.microsoft.com/en-us/library/aa263491(v=VS.60).aspx – jtolle Nov 05 '10 at 22:23

1 Answers1

16

The following assumes that VBA is still using the same garbage collection mechanism used in VB6 (which it very probably does).

VB6 used a reference-counting GC. The GC is triggered deterministically when the last reference to a given object is set to Nothing. Setting local references to Nothing is unnecessary, this happens as they go out of scope.

Every object implements a COM interface that takes care of the reference count for that object. Each assignment of an object reference updates the reference counters of the involved references (i.e. the counter of old object that was previously referenced gets decremented, and the new object’s counter is incremented). An object is garbage collected when its reference counter reaches 0.

Objects in circular references are thus never collected during the lifetime of a VBA application. What’s more, VBA doesn’t offer a way to break circular references. In VB6, weak references could be implemented via WinAPI functions.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    "Setting local references to Nothing is unnecessary, this happens as they go out of scope." <-- This should be tattooed inside every VBA/VB6 developer's eyelids! – Lunatik Nov 05 '10 at 13:27
  • @Lunatik - Agreed!! The number of posts I found when searching for GC information which say "It is best practise to set references to nothing" is truly terrifying. – Jon Artus Nov 05 '10 at 13:55
  • 6
    @Jon: unfortunately, this rumour isn’t entirely unfounded. VB6 seemed to have a bug that could cause some dangling references in class member variables (not local variables though). I don’t know if the exact source of this bug was ever tracked down but it became an established best-practice to use the `Class_Terminate` method to set all members to `Nothing`. – Konrad Rudolph Nov 05 '10 at 13:58
  • There is an edge case involving dangling ADO objects IIRC, but in the main it holds true. – Lunatik Nov 05 '10 at 15:02
  • 3
    VBA doesn't use garbage collection at all. When the reference count of an object goes to 0 the object is released. This is not garbage collection. – Bob77 Nov 05 '10 at 18:26
  • 6
    @Bob: depends on who you ask, both definitions exist (I’m guessing that your qualm is that in COM reference counting, there isn’t one central GC “service” which provides the GC, but rather each object has its own collecting mechanism built in). But I think I made it clear in my answer *what* is going on in VBA, whether one wants to call it a GC or not. – Konrad Rudolph Nov 05 '10 at 18:46
  • This is a very funny explanation of how things work. Objects don't get garbage collected, they are just destroyed (like `delete this` in C++). Providing a way to break cyclic references is not a task of VBA or VB6. It's just a matter of manually implementing a `Terminate` method or similar in some of the classes that form the chain. – wqw Nov 05 '10 at 20:57
  • 2
    @wqw: Implementing a `Class_Terminate` method will do nothing to break circular dependencies since that method will never be called. Of course, you could implement a *manually called* `Terminate` method, if that’s what you’re referring to. As for whether or not this is called “garbage collection”, once again: both definitions exist. Arguing against that is petty quibble. And whether or not this explanation is “funny” – it’s accurate. That’s what counts. – Konrad Rudolph Nov 06 '10 at 11:53
  • Look, cyclic references is a COM problem, not VBA, not VB6. You can't say objects are "collected" when they are self-destroying -- no one is collecting or destroying them i.e. there is no GC as a module/action/whatever. However, you can impl classes that use a custom memory manager which does not release memory immediately but uses a GC-style memory management (e.g. MSXML) This is way too custom, not COM specified behaviour and is the only case where we can speak of objects being GC-collected. – wqw Nov 07 '10 at 12:05
  • 3
    @Lunatik: the edge case was in DAO (not ADO): "[DAO provides] another example of poor teardown code. DAO has Close methods that must be called in the correct order, and the objects must be released in the correct order as well (Recordset before Database, for example). This single poor object model behavior has led to the misconception that VB leaks memory unless you explicitly set all the local variables to nothing at the end of a function. This is a completely false notion in a well-designed object model..." – onedaywhen Nov 08 '10 at 09:26
  • 8
    "...VB can clear the variables faster at the End Sub line than you can from code, and it checks the variables even if you explicitly release your references. Any effort you make is duplicated." Matthew Curland, Advanced VB6, p110. – onedaywhen Nov 08 '10 at 09:27