Managing Memory in COM
We continue on with our restaurant analogy to explain the concept of reference counting and COM object cleanup.
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."
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,
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
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.
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!"
Image by bridgesward from Pixabay