Hmmm...interesting discussion (which I missed originally).
Here's my 2 bucks worth.
From my C++ COM development I learned a lot of things, in particular about the internal working of a COM object as far as the low level C++ side is concerned and a few more general concepts, but the most important is this:
1. C++ is difficult; COM is hard; GOOD COM is very hard.
Throughout this thread, there was much mention of 'pointers' to objects and the like, but I believe there are some misconceptions about those magic 'pointers'.
In a nutshell, a COM Class holds an internal reference to the object it is describing and for all intents and purposes it is static. Think of it like a global lisp variable, or a private internal variable (for the .NET people).
Now, the FIRST time some chunk of code asks for this 'object', the COM component spins up an instance of it's internal object, and here's the important bit, creates a NEW POINTER TO THE INTERFACE of the OBJECT (AddRef), NOT a pointer to the internal object itself. The internal OBJECT is created only ONCE - EVER.
The next thing it does, is increment it's INTERFACE reference counter by one and pass back the pointer. At this time the calling code can do what it likes.
Remember, this is a pointer to an INTERFACE, NOT THE INTERNAL OBJECT as such. This process is repeated again and again as required by the clients of this COM object.
Now, to release or not? One of the classic 'bad' things about COM is memory management (leaks) and this comes about through the reference counting that the COM Object implements (badly in this case) and calling code.
Setting a COM object reference to nil/nothing/null is SUPPOSED to inform the COM CLASS OBJECT to decrement it's internal reference count by one. This process repeats again and again, untill the internal counter reaches 0. When this happens, the COM Class object destroys it's internal object (the real one you're interested in) and frees the memory allocated by this object back to the pool.
As far as the release question goes, I would adopt the same pattern as in C++ - if you NEW'em, DELETE'em...pure and simple. And I suspect the reason releasing the acad object doesn't ever get the count to 0 is that AutoCAD itself is hanging onto some interface pointers for internal reasons (vlisp being one). Let's face it, you wouldn't want the reference count to the Acad Application itself to reach 0 whilst your code was running would you?
Just some ramblings that may or may not help.
Cheers,
Glenn.