Is it necessary to call Marshal.ReleaseComObject in C#4 when doing COM? - com

I have VS2010 and added a reference to a COM library to my project and VS embedded a primary interop inside the project.
If I reference objects from the COM library and I want to dispose of them quickly without waiting for the GC, is it needed to call ReleaseComObject ?

Marshal.ReleaseComObject provides a way to immediately drop references to this COM object from everywhere it is being consumed within managed code (because it releases the underlying IUnknown from the RCW that is holding it).
As Hans notes, the generally right course is to simply null your object allow the CLR and GC to do the COM object destruction at the appropriate time.
However, in situations where you need immediate action (COM object holds expensive/scarce resources, or perhaps during shutdown where the sequencing is very complex), calling ReleaseComObject can be the right thing to do.
Martyn

There are two types of approaches in terms of cleaning memory.
Reference Counting Algorithms
Garbage Collection
COM components use reference counting algorithm to reclaim memory. Whenever you do not need a reference of a com component you can call it. But Usually my approach is creating a virtual stack and deleting references like the source code below in C#. .NET guarantees as long as RCW is alive COM components is alive. When RCW is garbage collected release method is invoked. It is not necessary to call release in your code. But it does not effect gc cycles.
void DoSth
{
{
RunTimeCallableWrapper area for the code
ReleaseComObject
}
}

Related

Access violation in WCF with COM object after garbage collection

I have a self-hosted WCF application where the service objects (per call, single concurrency) use embedded COM objects (referenced from the class throughout the call) built on a platform called Clarion. The COM instances are created and destroyed together with the service objects. However, underneath they access a singleton repository which takes long time to initialise (very similar to this: Startup Code for Loading COM Object for WCF Service). So a first call is very long. Hence, I must call it on startup.
If I don't instantiate the COM object on startup, everything is fine (except for the long first call). But if I do, after the garbage collection the next request will crash with access violation exception when trying to access the COM.
The service objects implement IDisposable where all the COM objects are nicely released using Marshal.ReleaseComObject.
The startup call also releases the COM object.
My guess is that the startup COM gets somehow reused or recycled. I don't want it to! Can I make sure it dies forever? Or if it's not possible, can I mark it not for garbage collection? Obviously, GC.KeepAlive is irrelevant here, because these are different threads in different methods.
More details: the COM objects were made MTA-capable recently. They are thread-safe and fully concurrent, but before, when they were STA only, there was no such issue. Also, nothing bad happens outside of WCF when these guys run in separate threads.
OK. Looks like I'm on it.
It's the bloody hidden singleton objects or, rather, a runtime library of the platform the COM is written on (SoftVelocity Clarion). It got deallocated for some reason when the startup COM got killed, probably because the reference count went down and it was time to unload the DLL itself. Although when I tweaked DllCanUnloadNow, it did not help, but I'll figure out where it's coming from.
EDIT: Clarion support of COM objects is not straightforward. The code, generated by templates, performs allocation and deallocation of the database dictionary (DctInit and DctKill respectively) and some specific classes in the main program, which ends when the main thread ends. However, in MTA COM objects end of the main thread does not mean end of the program. Hence, the easiest solution is to embed code to prevent execution of DctKill.
Also, do not forget to call AttachThreadToClarion(TRUE) in .Destruct methods, since the garbage collection thread will be different.
This issue may surface in older generation IDEs where a runtime or global objects are used extensively. Beware.

VB.NET Track COM RCW error

I have a really big project that I can not easily strip down.
When the application is being closed, I get the error
"InvalidComObjectException: A COM object that has been disconnected from the RCW can not be used."
Details:
System.Runtime.InteropServices.InvalidComObjectException has occured.
HResult=-2146233049
Message=A COM object that has been disconnected from its RCW can not be used.
Source=mscorlib
StackTrace:
at System.StubHelpers.StubHelpers.StubRegisterRCW(Object pThis)
InnerException:
Unfortunately I can not see what COM object this is about.
Does anybody know how I can find that out? Unfortunately I can't read ASM to analyze the disassembly.
There are some steps you could try and since you haven't posted any code I will try to enumerate some of the most common key factors...
First, there is no order when disposing objects. If a close/dispose/finalize action is invoked, object C might be disposed before object A and if some object is still alive it might try to access an already disposed object.
Second, beware of events. It's very common to get errors about accessing a disposed object originated from an event call.
Third, do not dispose objects inside an event scope nor destructors. Create your own method to free your object(s).
Since you don't know which COM object is the culprit, I suggest you look for the ones that you do close, dispose, disconnect, etc...
You might want to read this blog in order to better understand how RCW's work and also to help you with your problem.
Edit:
After reading your comment, I felt I should add two possible causes:
If after removing Microsoft.VisualBasic runtime methods you've solved your problem, then I suspect that inside one, or more, of those methods you have incremented the count of a reference to one, or more, of your COM(s) and did not release properly.
Be sure to ReleaseComObject checking the reference count until it's 0 and then set it to nothing(VB) or null(C#) and let the Garbage Collector do the rest.
The other option is that one of those methods tried to access an already disposed reference to a COM object, resulting in a RCW error, since is no longer callable.
As a final comment, after releasing the COM object always set it to nothing or null, this will release the reference to the variable and you can always check it's availability anywhere in the code.

Is there a counterpart to "CreateInstance"?

We have some code that uses MSXML, and does this to create the XML document object:
MSXML2::IXMLDOMDocumentPtr doc_in;
doc_in.CreateInstance("Msxml2.DOMDocument.6.0");
Once we're finished with doc_in, how do we destroy it? Is it just automatically destructed when doc_in goes out of scope, or what?
COM object lifetime management builds on reference counting via IUnknowns methods AddRef() and Release(). For details see "Using and Implementing IUnknown", in particular "Rules for Managing Reference Counts".
On top of that smart pointers are used, most commonly ATLs CComPtr/CComQIPtr and _com_ptr_t.
So, if you're dealing with a plain pointer to a COM instance, you have to Release() manually to relinquish ownership.
If you have a smart pointer to a COM instance, the Release() should be done for you when the smart pointer instance goes out of scope - but to be sure take a look at the documentation for the actual smart pointer class you are using.
If IXMLDOMDocumentPtr is a smart pointer (as it looks like) then it will take care of calling doc_in.Release() for you.

VBA Garbage Collector Details

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!
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.

Is object clearing/array deallocation really necessary in VB6/VBA (Pros/Cons?)

A lot of what I have learned about VB I learned from using Static Code Analysis (Particularly Aivosto's Project Analyzer). And one one of things it checks for is whether or not you cleared all objects and arrays. I used to just do this blindly because PA said so. But now that I know a little bit more about the way VB releases resources, it seems to me that these things should be happening automatically. Is this a legacy feature from pre VB6, or is there a reason why you should explicitly set objects back to nothing and use Erase on arrays?
Matt Curland, author of Advanced Visual Basic 6, who knows more about Visual Basic than most of us ever will, thinks it is wasted effort. Consider this quote (p110) about DAO, the COM data access library that primarily targets the Access Database Engine:
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. 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.
The problem, as I understand it, has to do with the fact that VB6 (and its predecessors) has its roots in COM, and its reference-counting garbage collection system.
Imagine, for instance, that you declare a refernece to an object from a 3rd party library. That object has a COM reference count that is used both to keep it alive and to determine when it should be destroyed. It isn't destroyed when you set it to Nothing, but when the object's reference count reaches zero.
Now, not all COM components were written in Visual Basic. Some were written in C or C++. Structured exception handling didn't exist across all languages. So if an error occurred, the reference count on the object was not guaranteed to be properly reduced, and COM objects were known to hang around longer than they were intended to. This wasn't a problem with Visual Basic, per se. It was a COM problem. (And that, you might note, is why .NET doesn't use reference counting.)
That's why Visual Basic developers became obsessive about releasing object references prior to exiting routines. You simply don't know what a component you're allocating is creating under the hood. But when you release your reference to it, you're at least releasing your reference count to it. It became almost a religious mantra. Declare, use, release. It was the COM way of doing things.
Sure, Visual Basic might be better or faster at dereferencing variables I declared on the stack. But dammit, I want it to be OBVIOUS that those objects were released. A little assurance goes a long way when you're trying to track down a memory leak.
Have you read this Aivosto web page (from the creators of Project Analyzer)?
If you are using static variables,
it's important to reclaim the memory
they occupied when you don't need the
variables any more. With dynamic
variables memory isn't so much of a
problem, because they are destroyed
when the procedure ends.
In other words, you don't need to worry about clearing ordinary, non-static, local variables.
I always do it for good practice, you never know what an exception might do if you fall in one and your objects are not deallocated. You should relase them in finally statements and ensure they are not using any memory otherwise you may run into a memory leak.
I had an issue inside of a simple time off tracker system where the server kept on crashing randomly, it took weeks to determine it was a memory leak of an object that was supposed to self destruct on its own. My code was being thrown into an exception and never cleaned up after itself causing the server (the actual web site not the entire server) to go down.
Yes, set all objects to Nothing and clean up as much as you can. VB6 is notorious for having memory leaks when not cleaning up your stuff. Garbage collection was sub-par in VB6/VBA.