How to deallocate COM server object forcefully from C# .NET - c#

Can I know how to deallocate COM server object forcefully from C# .NET if particular condion fails or the object is partially constructed?
The problem is I am using that COM server using DCOM mechanism; in the worst case, when the object is not created fully and I am coming out of application since failure, the COM object is still in memory (showed in COM+ Application component services). If its going beyond some limits, it leads to memory leak and crash. But if its manageable amount of failures, its getting deleted after some point of times.
Sample:-
Calculator.App objApp = new Calculator.App();
if( !obj.CanBeUsed() )
{
//how to deallocate the COM object objApp
}
Note:
There is a method GC.Collect() used by Garbase Collector to de-allocate from the heap memory forcefully. Whether I can use this method or .NET franework is giving anyother solution for this particular case?

Like this:
System.Runtime.InteropServices.Marshal.ReleaseComObject(objApp);

You should try Marshal.FinalReleaseComObject method.
The FinalReleaseComObject method
releases the managed reference to a
COM object. Calling this method is
equivalent to calling the
ReleaseComObject method in a loop
until it returns 0 (zero).
When the reference count on the COM
object becomes 0, the COM object is
usually freed, although this depends
on the COM object's implementation and
is beyond the control of the runtime.
However, the RCW can still exist,
waiting to be garbage-collected.
The COM object cannot be used after it
has been separated from its underlying
RCW. If you try to call a method on
the RCW after its reference count
becomes 0, a InvalidComObjectException
will be thrown.

Related

Outlook Addin: How to actively release memory as suggested by Microsoft documentation?

The outlook addin tries to retrieve Outlook.Exceptions correctly. I found the following documentation:
https://learn.microsoft.com/de-de/office/client-developer/outlook/pia/how-to-find-a-specific-appointment-in-a-recurring-appointment-series
There it says:
[...] When you work with recurring appointment items, you should release any prior references, obtain new references to the recurring appointment item before you access or modify the item, and release these references as soon as you are finished and have saved the changes. This practice applies to the recurring AppointmentItem object, and any Exception or RecurrencePattern object. To release a reference in Visual Basic, set that existing object to Nothing. In C#, explicitly release the memory for that object.
[...]
Now my question is how do I do that? The example on the referenced page does not explicitly release the memory?
Would it be sufficient to set appt to null?
Setting to null is definitely not enough. In this case, additionally you have to force the garbage collector to swipe the heap as soon as possible. You do this correctly with calls to GC.Collect() and GC.WaitForPendingFinalizers(). Calling twice is safe, end ensures that cycles are definitely cleaned up too.
But I'd recommend using System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. This is particularly important if your add-in attempts to enumerate more than 256 Outlook items in a collection that is stored on a Microsoft Exchange Server (this number was increased in latest versions). If you do not release these objects in a timely manner, you can reach the limit imposed by Exchange on the maximum number of items opened at any one time.
The ReleaseComObject method is used to explicitly control the lifetime of a COM object used from managed code. You should use this method to free the underlying COM object that holds references to resources in a timely manner or when objects must be freed in a specific order.
Every time a COM interface pointer enters the common language runtime (CLR), it is wrapped in an RCW.
The RCW has a reference count that is incremented every time a COM interface pointer is mapped to it. The ReleaseComObject method decrements the reference count of an RCW. When the reference count reaches zero, the runtime releases all its references on the unmanaged COM object, and throws a System.NullReferenceException if you attempt to use the object further. If the same COM interface is passed more than one time from unmanaged to managed code, the reference count on the wrapper is incremented every time, and calling ReleaseComObject returns the number of remaining references.
The ReleaseComObject method enables you to force an RCW reference count release so that it occurs precisely when you want it to. However, improper use of ReleaseComObject may cause your application to fail, or may cause an access violation.
Memory management in C# (CLR runtime) is automatic and employs a garbage collector.
Periodically, the garbage collector checks for unreachable objects to be reclaimed. This process is not deterministic unless you force it (but normally you shouldn't).
To have the memory of an object freed, you simply have to make it unreachable: this can happen in various combinations of setting to null all the references to the offending object or, letting go out of scope all of them (provided that you didn't assign it to fields of properties).

Releasing Com Objects Doesnt Affect Memory Usage

When I release com objects by Marshall.ReleaseComObject method, memory usage of application doesnt change. Instead of using Marshall.ReleaseComObject, using Garbage Collector (GC.Collect()) can release memory area of com objects but the UI is getting slow down.
So my question is, what is the best method to release com objects?
Athough a bit outdated (as from ArcGIS 10.0) the rules for releasing and how to do so are pretty well described on http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#/Releasing_COM_references/0001000004tm000000/.
There are two ways to do this. Either by using Marshal.ReleaseCOMObject or by the ComReleaser-class which essentially is a wrapper around the former. However you may have multiple references to the exact same com-object, which is why calling ReleaseComObject will not finally release the object, but simply decrease the internal reference-counter by one. Only when that counter is equal to zero the object will actually be released. See here for example:
var f1 = featureClass.GetFeature(1);
// retrieve the exact same feature again
var f2 = featureClass.GetFeature(1);
Although from a .NET-perspective f1 and f2 are comlpletely different objects, the underlying com-object is the same (assuming unique-instancing, which is out of the scope of this question). When calling Marshal.ReleaseComObject on either f1 or f2, you will only decrease the internal reference-counter for this com-object by one, leaving one reference alive.
GC.Collect however has no effect as it can´t handle unmanaged resources which com-objects are. The garbage-collector is only able to release managed resources. Calling GC.Collect will thus only - if at all - release the runtime-callable-wrapper, which is a managed wrapper around the unmanaged object. The latter however still exists in memory and is likely to produce a dead-leak.
Having said this the only way to finally release a com-objects is to call Marshal.ReleaseComObject in a loop until the reference-counter is zero.
while(Marshal.ReleaseComObject(myObject) > 0);
Afterwards you may or may not call GC.Collect. However I won´t suggest to do so, as the garbage-collector knows best when to release a mananed object. Forcing it to do so will at best work as expected, at worst however only mke your code slow without having any positive effect. GC is un-determinsitc process, you can´t really influence it.
Best way to do is using ComReleaser or Marshal.ReleaseComObject methods. Calling GC.Collect method too much will cause to slow down of your application. Let GC do its job when needed.
Try this,
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oApp);
oApp = null; // Set each COM Object to null
//
// After all of the COM objects have been released and set to null, do the following:
GC.Collect(); // Start .NET CLR Garbage Collection
GC.WaitForPendingFinalizers(); // Wait for Garbage Collection to finish
If object implement finalizer, call gc means put this object reference in finalization queue, means it doesnt release immediately.

Proper way of releasing COM objects?

Sometimes when I end the application and it tries to release some COM objects, I receive a warning in the debugger:
RaceOnRCWCleanUp was detected
If I write a class which uses COM objects, do I need to implement IDisposable and call Marshal.FinalReleaseComObject on them in IDisposable.Dispose to properly release them?
If Dispose is not called manually then, do I still need to release them in the finalizer or will the GC release them automatically? Now I call Dispose(false) in the finalizer but I wonder if this is correct.
The COM object I use also have an event handler which the class listens to. Apparently the event is raised on another thread, so how do I correctly handle it if it is fired when disposing the class?
First - you never have to call Marshal.ReleaseComObject(...) or Marshal.FinalReleaseComObject(...) when doing Excel interop. It is a confusing anti-pattern, but any information about this, including from Microsoft, that indicates you have to manually release COM references from .NET is incorrect. The fact is that the .NET runtime and garbage collector correctly keep track of and clean up COM references.
Second, if you want to ensure that the COM references to an out-of-process COM object is cleaned up when your process ends (so that the Excel process will close), you need to ensure that the Garbage Collector runs. You do this correctly with calls to GC.Collect() and GC.WaitForPendingFinalizers(). Calling twice is safe, end ensures that cycles are definitely cleaned up too.
Third, when running under the debugger, local references will be artificially kept alive until the end of the method (so that local variable inspection works). So a GC.Collect() calls are not effective for cleaning object like rng.Cells from the same method. You should split the code doing the COM interop from the GC cleanup into separate methods.
The general pattern would be:
Sub WrapperThatCleansUp()
' NOTE: Don't call Excel objects in here...
' Debugger would keep alive until end, preventing GC cleanup
' Call a separate function that talks to Excel
DoTheWork()
' Now Let the GC clean up (twice, to clean up cycles too)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
Sub DoTheWork()
Dim app As New Microsoft.Office.Interop.Excel.Application
Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add()
Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1")
app.Visible = True
For i As Integer = 1 To 10
worksheet.Cells.Range("A" & i).Value = "Hello"
Next
book.Save()
book.Close()
app.Quit()
' NOTE: No calls the Marshal.ReleaseComObject() are ever needed
End Sub
There is a lot of false information and confusion about this issue, including many posts on MSDN and on StackOverflow.
What finally convinced me to have a closer look and figure out the right advice was this post https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/ together with finding the issue with references kept alive under the debugger on some StackOverflow answer.
Based on my experience using different COM objects (in-process or out-of-process) I would suggest one Marshal.ReleaseComObject per one COM/ .NET boundary crossing (if for an instance you reference COM object in order to retrieve another COM reference).
I have run into many issues just because I decided to postpone COM interop cleanup to GC.
Also please notice, I never use Marshal.FinalReleaseComObject - some COM objects are singletons and it doesn't work well with such objects.
Doing anything in managed objects inside finalizer (or Dispose(false) from the well-known IDisposable implementation) is forbidden. You must not rely on any .NET object reference in the finalizer. You can release IntPtr, but not COM object as it could already be clean up.
There's an article here on that: http://www.codeproject.com/Tips/235230/Proper-Way-of-Releasing-COM-Objects-in-NET
In a nutshell:
1) Declare & instantiate COM objects at the last moment possible.
2) ReleaseComObject(obj) for ALL objects, at the soonest moment possible.
3) Always ReleaseComObject in the opposite order of creation.
4) NEVER call GC.Collect() except when required for debugging.
Until GC naturally occurs, the com reference will not be fully released. This is why so many people need to force object destruction using FinalReleaseComObject() and GC.Collect(). Both are required for dirty Interop code.
Dispose is NOT automatically called by the GC. When an object is being disposed, the destructor is called (in a different thread). This is usually where you could release any unmanaged memory, or com references.
Destructors: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
... when your application encapsulates unmanaged resources such as windows, files, and network connections, you should use destructors to free those resources. When the object is eligible for destruction, the garbage collector runs the Finalize method of the object.

GC.Collect versus Marshal.ReleaseComObject and RCW

I have a COM object reference in my C# that on occasion I require to be discarded by being set to Null then recreated. It seems that there is some caching going on or something that can result in the 'COM object has been seperated from it's underlying RCW' type of error. I got around this by forcing a GC.Collect immediately after setting the object to Null to discard the RCW but this heavy handed and inefficient approach is bad.
I wanted to use Marshal.ReleaseComObject but that just decrements the ref count and the issue remains until the GC actually runs. (Not to mention calling that is also a bad idea in general)
How can I ensure that upon recreation of the COM reference I get a new RCW and everything behaves as it should?

Where can I find more detail on disposal of COM resources in .NET?

The background for my question is this: I am converting a message processing app that uses many COM components from VB6 to C#. Many of the COM components in the application are fine-grained components that are used in high numbers and frequency within message processing loops. I am seeing a massive (and progressively growing) increase in memory usage when processing a set of test messages in the C# app as compared to the VB6 app. I used a memory profiler on the application that confirmed that the high memory usage was due to live instances of COM objects on the application's unmanaged heap. I know that these components are not being "leaked" due to live references because if I put a GC.Collect() at the core of the message processing loop, the memory usage is flat and nearly identical to the VB6 app (although the performance degrades horribly as one would expect).
I have read everything I can find on the multi-generation garbage collector in C#, runtime callable wrappers, unmanaged resource memory allocation, Marshal.ReleaseComObject(), Marshal.FinalReleaseComObject(), etc. None of it explains why the application is holding onto live COM objects in the unmanaged heap when the corresponding RCWs are eligible for garbage collection.
In some articles, I have seen allusions to the possibility that the actual implementation of the garbage collector in C# may involve optimizations such as not performing collection of all eligible objects in a particular generation. If this or something like it were true, it could explain why eligible RCWs and their corresponding COM objects are not collected and destroyed. Another explanation could be if the destruction of a COM object in the unmanaged heap is not directly tied to the collection of its corresponding RCW. I have not found anything that offers this degree of detail on how COM objects are handled in .NET. I need to understand this better because my app's memory usage is currently unacceptable. Any pointers or recommendations would be greatly appreciated.
Edit: I should add that I am quite familiar with finalizers (which are not documented to exist on RCWs) and the IDisposable interface (which RCWs do not implement). To the best of my understanding, Marshal.ReleaseComObject() is the proper method of explicitly "disposing" of a COM reference. I was careful to add that statement for every known usage of a COM object in my app and it resulted in no difference in memory usage.
Further, it is not clear why a lack of disposal or finalization code could be the problem when the addition of an explicit GC.Collect() results in no memory problems. Neither Dispose() nor the presence of a finalizer result in the actual collection of objects. The former permits an object to suppress its finalization step (if any) and the latter allows for the cleanup of unmanaged resources of which none are exposed in an RCW.
Are you implementing IDisposable properly in the classes that instantiate your COM objects?
You need to implement IDisposable and dispose of your COM RCW's in the Dispose() method. Then all code that instantiates classes that implement IDisposable should call it either explicitly or by using a using() statement, like so:
var first = new DisposableObject();
...
first.Dispose();
and
using(var first = new DisposableObject())
{
...
}
IDisposable is the only way to get the CLR to dispose of these objects in a timely manner and to make sure you lose COM references.
Use a Finalizer or destructor to clean up the memory used by the COM objects.
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
Alternatively, if you want the objects to clean up immediately, you can implement IDispose, and use a using statement in your code that instantiates the COM object.

Categories