Managing Memory in COM

In my article on Memory Management in VBA, I used the following definition for "memory management":

Memory management is the process of reserving computer memory for your program's use and then releasing it when it is no longer needed.

COM relies on a memory management technique known as "Reference Counting."

Reference Counting

COM objects self-destruct.

More precisely, COM objects mark themselves as eligible for destruction when the number of items referencing it falls to zero.  The COM server (C++) is responsible for maintaining its own reference count.  However, it can only do this with help from the COM client (VBA).  Consider this example:

Dim ObjA As Collection, ObjB As Collection
Set ObjA = New Collection   'RefCount = 1
Set ObjB = ObjA             'RefCount = 2
Set ObjA = Nothing          'RefCount = 1
Set ObjB = Nothing          'RefCount = 0

In the above code, ObjA and ObjB both refer to the same COM object.  The COM object remains alive following the Set ObjA = Nothing line because ObjB still has a reference to it.  It's not until after calling Set ObjB = Nothing and the object's reference count reaches zero that its memory is freed.

A note about C++ and VBA: COM is a binary interface standard, which means that any programming language can act as a COM client and any programming language can act as a COM server.  For our practical purposes as Access developers, though, the most common scenario is for a COM server (such as excel.exe) to be written in C++ and a COM client (your Access front-end application) to be written in VBA.  Since the terms "server" and "client" can cause confusion due to their ambiguity in the English language, I'll use "C++" and "VBA" as stand-ins for "COM server" and "COM client" for the purposes of our discussion here.

Role of the IUnknown Interface

As VBA developers, we are only involved in the reference counting indirectly.

When we create new object variables using Dim ... As New or Set ... = New ... the reference count increases by 1.  When we call Set ... = Nothing or our object variable goes out of scope, the reference count decreases by 1.

Behind the scenes, though, the VBA language itself is calling the AddRef and Release methods of the IUnknown interface.

Remember, IUnknown is an interface.  That means it is up to the COM object developer to decide how exactly to implement these two methods.  The obvious implementation–and what I expect almost every COM object uses–is to maintain an internal counter variable.  

Each time AddRef is called, the COM object increments the counter by one and returns the new reference count.  Each time Release is called, the COM object decrements the counter by one and returns the new reference count.

A less efficient–but still functional–implementation would be to maintain an internal string of tally marks.  Each time AddRef is called, a pipe character is appended to a string variable named Tally and the length of the string is returned.  When Release is called, the Tally string is reduced by one character.  My point here is not that you would do something like this, only that you could do something like this.

Let's take these concepts and apply them to a real-ish world model.


Welcome to the  COM and Get It!  Diner

The COM and Get It! is a very special diner.

It's open whenever a customer wants to eat there.  It has unlimited seating. Once it's open, it will stay open forever as long as there is at least one customer inside.  But, if all the customers leave–no matter the time of day–it closes its doors and sends the staff home.  If a new customer comes by after the doors have been closed, it will immediately reopen...but in a different location than before.

It's like a magical "Restaurant of Requirement."

Deciding when to open and close the doors of the COM and Get It! requires keeping track of how many customers are in the diner at any given time.  The person responsible for this task is the diner's host, Wink Nuno, a quiet man with a mysterious past.

Sacred Rules for Customers (COM client: VBA)

If you want to eat at the COM and Get It! there are two sacred rules you must follow:

  • You tell Wink when you arrive
  • You tell Wink when you leave

AddRef  when you arrive at the restaurant

If you haven't figured it out yet, Wink Nuno is the restaurant's IUknown interface.

Telling Wink that you have arrived is the equivalent of calling the AddRef method of the IUknown interface when you create a reference to a COM object.

Release  when you leave

On your way out the door, you need to tell Wink you're leaving.  Otherwise, how will he know you've left?

Wink's Sacred Duties (COM Server: C++)

As the diner host, Wink has two sacred duties of his own:

  • Calling in the employees and opening the diner when the first customer arrives
  • Sending the employees home and closing up when the last customer leaves

Remember, Wink can't do his job as diner host if you don't do your job as a customer.

If you don't AddRef when you arrive, you (or someone else) could get locked in the bathroom

If you forget to check in with Wink when you arrive, his customer count will always be low.  Instead of closing up when the last customer leaves, he'll close up when the second-to-last customer leaves.  If you're the last customer left when the diner closes up, you could be stuck in the bathroom for all eternity.

But it's even worse than that.  Bear with me while I stretch this metaphor.

Remember, once the COM and Get It! closes its doors, it leaves its current location and reappears somewhere completely different (i.e., some other arbitrary location in memory).  But as far as you know, you are still in the diner's bathroom going about your business in blissful ignorance.  Imagine the shock on the motorists faces when it turns out that what you think is a diner has been replaced with a four-lane highway (who knows what you'll find in unsafe memory).

Talk about a hard crash...

If you don't Release when you leave, the staff can never go home

Finally, if you walk out of the diner without telling Wink you're leaving, he will always think there is one more customer left.  The staff will never get to go home to their families.

Of course, you know that you left, so you assume that the restaurant must have closed.  When you get hungry, you won't go back to the previous location of the restaurant.  Instead, you'll just summon a new instance of the COM and Get It!

And, since you were a jerk before and broke the sacred rule about telling Wink when you leave, there's no reason to think you won't break that rule again.  The result is that every time you get a little hungry, ten more of Wink's friends need to come in and open everything up just to fry you some bacon (mmm....bacon).

Really, though, leaving without telling Wink is kind of a jerk move.  

For a man of mystery, Wink has a lot of friends.  But he doesn't have that many friends.  At some point, all these open restaurant instances (memory leaks) will start to add up.  Then, one day in the middle of a particularly intense bacon craving, Wink will throw up his hands in frustration and say to you, "I'm sorry, but I'm all out of friends" (or "memory" or "system resources").

"No more restaurant of requirement for you!"

Referenced articles

Memory Management in VBA: 3 Keys to Avoiding Memory Leaks
Managing memory in VBA is a piece of cake, especially if you follow three simple guidelines.
The IUnknown Interface
All COM objects are required to support at least one interface: the IUnknown interface. In this short article, we explore the three methods of IUnknown.

Image by bridgesward from Pixabay