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?
Related
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).
Today I have seen a piece of code that first seemed odd to me at first glance and made me reconsider. Here is a shortened version of the code:
if(list != null){
list.Clear();
list = null;
}
My thought was, why not replace it simply by:
list = null;
I read a bit and I understand that clearing a list will remove the reference to the objects allowing the GC to do it's thing but will not "resize". The allocated memory for this list stays the same.
On the other side, setting to null would also remove the reference to the list (and thus to its items) also allowing the GC to do it's thing.
So I have been trying to figure out a reason to do it the like the first block. One scenario I thought of is if you have two references to the list. The first block would clear the items in the list so even if the second reference remains, the GC can still clear the memory allocated for the items.
Nonetheless, I feel like there's something weird about this so I would like to know if the scenario I mentioned makes sense?
Also, are there any other scenarios where we would have to Clear() a list right before setting the reference to null?
Finally, if the scenario I mentioned made sense, wouldn't it be better off to just make sure we don't hold multiple references to this list at once and how would we do that (explicitly)?
Edit: I get the difference between Clearing and Nulling the list. I'm mostly curious to know if there is something inside the GC that would make it so that there would be a reason to Clear before Nulling.
The list.Clear() is not necessary in your scenario (where the List is private and only used within the class).
A great intro level link on reachability / live objects is http://levibotelho.com/development/how-does-the-garbage-collector-work :
How does the garbage collector identify garbage?
In Microsoft’s
implementation of the .NET framework the garbage collector determines
if an object is garbage by examining the reference type variables
pointing to it. In the context of the garbage collector, reference
type variables are known as “roots”. Examples of roots include:
A reference on the stack
A reference in a static variable
A reference in another object on the managed heap that is not eligible for garbage
collection
A reference in the form of a local variable in a method
The key bit in this context is A reference in another object on the managed heap that is not eligible for garbage collection. Thus, if the List is eligible to be collected (and the objects within the list aren't referenced elsewhere) then those objects in the List are also eligible to be collected.
In other words, the GC will realise that list and its contents are unreachable in the same pass.
So, is there an instance where list.Clear() would be useful? Yes. It might be useful if you have two references to a single List (e.g. as two fields in two different objects). One of those references may wish to clear the list in a way that the other reference is also impacted - in which list.Clear() is perfect.
This answer started as a comment for Mick, who claims that:
It depends on which version of .NET you are working with. On mobile platforms like Xamarin or mono, you may find that the garbage collector needs this kind of help in order to do its work.
That statement is begging to be fact checked. So, let us see...
.NET
.NET uses a generational mark and sweep garbage collector. You can see the abstract of the algorithm in What happens during a garbage collection
. For summary, it goes over the object graph, and if it cannot reach a object, that one can be erased.
Thus, the garbage collector will correctly identify the items of the list as collectible in the same iteration, regardless of whatever or not you clear the list. There is no need to decouple the objects beforehand.
This means that clearing the list does not help the garbage collector on the regular implementation of .NET.
Note: If there were another reference to the list, then the fact that you cleared the list would be visible.
Mono and Xamarin
Mono
As it turns out, the same is true for Mono.
Xamarin.Android
Also true for Xamarin.Android.
Xamarin.iOS
However, Xamarin.iOS requires additional considerations. In particular, MonoTouch will use wrapped Objective-C objects which are beyond the garbage collector. See Avoid strong circular references under iOS Performance. These objects require different semantics.
Xamarin.iOS will minimize the use of Objetive-C objects by keeping a cache:
C# NSObjects are also created on demand when you invoke a method or a property that returns an NSObject. At this point, the runtime will look into an object cache and determine whether a given Objective-C NSObject has already been surfaced to the managed world or not. If the object has been surfaced, the existing object will be returned, otherwise a constructor that takes an IntPtr as a parameter is invoked to construct the object.
The system keeps these objects alive even there are no references from managed code:
User-subclasses of NSObjects often contain C# state so whenever the Objective-C runtime performs a "retain" operation on one of these objects, the runtime creates a GCHandle that keeps the managed object alive, even if there are no C# visible references to the object. This simplifies bookeeping a lot, since the state will be preserved automatically for you.
Emphasis mine.
Thus, under Xamarin.iOS, if there were a chance that the list might contain wrapped Objetive-C objects, this code would help the garbage collector.
See the question How does memory management works on Xamarin.IOS, Miguel de Icaza explains in his answer that the semantics are to "retain" the object when you take a reference and "release" it when the reference is null.
On the Objetive-C side, "release" does not mean to destroy the object. Objetive-C uses a reference count garbage collector. When we "retain" the object the counter is incremented and when we "release" the counter is decreased. The system destroys the object when the counter reaches zero. See: About Memory Management.
Therefore, Objetive-C is bad at handling circular references (if A references B and B references A, their reference count is not zero, even if they cannot be reached), thus, you should avoid them in Xamarin.iOS. In fact, forgetting to decouple references will lead to leaks in Xamarin.iOS... See: Xamarin iOS memory leaks everywhere.
Others
dotGNU also uses a generational mark and sweep garbage collector.
I also had a look at CrossNet (that compiles IL to C++), it appears they attempted to implement it too. I do not know how good it is.
It depends on which version of .NET you are working with. On mobile platforms like Xamarin or mono, you may find that the garbage collector needs this kind of help in order to do its work. Whereas on desktop platforms the garbage collector implementation may be more elaborate. Each implementation of the CLI out there is going to have it's own implementation of the garbage collector and it is likely to behave differently from one implementation to another.
I can remember 10 years ago working on a Windows Mobile application which had memory issues and this sort of code was the solution. This was probably due to the mobile platform requiring a garbage collector that was more frugal with processing power than the desktop.
Decoupling objects helps simplify the analysis the garbage collector needs to do and helps avoid scenarios where the garbage collector fails to recognise a large graph of objects has actually become disconnected from all the threads in your application. Which results in memory leaks.
Anyone who believes you can't have memory leaks in .NET is an inexperienced .NET developer. On desktop platforms just ensuring Dispose is called on objects which implement them may be enough, however with other implementations you may find it is not.
List.Clear() will decouple the objects in the list from the list and each other.
EDIT: So to be clear I'm not claiming that any particular implementation currently out there is susceptible to memory leaks. And again depending on when this answer is read the robustness of the garbage collector on any implementation of the CLI currently out there could have changed since the time writing this.
Essentially I'm suggesting if you know that your code needs to be cross platform and used across many implementations of the .NET framework, especially implementations of the .NET framework for mobile devices, it could be worth investing time into decoupling objects when they are no longer required. In that case I'd start off by adding decoupling to classes that already implement Dispose, and then if needed look at implementing IDisposable on classes that don't implement IDisposable and ensuring Dispose is called on those classes.
How to tell for sure if it's needed? You need to instrument and monitor the memory usage of your application on each platform it is to be deployed on. Rather than writing lots of superfluous code, I think the best approach is to wait until your monitoring tools indicate you have memory leaks.
As mentioned in the docs:
List.Clear Method (): Count is set to 0, and references to other
objects from elements of the collection are also released.
In your 1st snippet:
if(list != null){
list.Clear();
list = null;
}
If you just set the list to null, it means that you release the reference of your list to the actual object in the memory (so the list itself is remain in the memory) and waiting for the Garbage Collector comes and release its allocated memory.
But the problem is that your list may contain elements that hold a reference to another objects, for example:
list → objectA, objectB, objectC
objectB → objectB1, objectB2
So, after setting the list to null, now list has no reference and it should be collected by Garbage Collector later, but objectB1 and objectB2 has a reference from objectB (still be in the memory) and because of that, Garbage Collector need to analyse the object reference chain. To make it less confusing, this snippet use .Clear() function to remove this confusion.
Clearing the list ensures that if the list is not garbage collected for some reason, then at the very least, the elements it contained can still be disposed of.
As stated in the comments, preventing other references to the list from existing requires careful planning, and clearing the list before nulling it doesn't incur a big enough performance hit to justify trying to avoid doing so.
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.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Garbage Collection: Is it necessary to set large objects to null in a Dispose method?
Does anyone know if explicitly de-referencing an object;
finalResults = null;
gives the garbage collector any more of a nudge to clean up? I have a rather large object (not huge, but big enough that I don't want it hanging around for too long after it's been used)
Would the above help or is it pointless code? I am specifically avoiding programatically talking to the GC itself, I just need to know if the above would act as any sort of prompt/hint to it.
Is finalResults = null; pointless?
Not enough information.
If finalResults is a local variable then it is pointless and potentially even harmful. You're just interfering with the optimizer.
If it is a class-member (property or field) it may be useful. Not very often but if you have a point in time where you can be very sure the value won't be used anymore then it won't hurt to set it to null.
As far as I know, not really.
The main rule the garbage collector uses (to work out if it needs to do a collection) is to work out if there is enough space in the Gen-0 heap to allocate a new object when it's asked for. If it can't allocate the object, it then performs a collection.
Collections are messy and noisy (because of heap compression, promotion from objects from Gen--0 to Gen-1 and Gen-1 to Gen-2) so it's best to leave the GC to worry about it.
The GC will finalize your object when it needs to, so don't worry about it sitting around.
If you're really concerned, then in a debug build try putting a call to
GC.Collect();
Where you'd set the object to Null, and see what affect it has, but really my best advise is to not lose any sleep about it.
Don't spend any time setting variables to null. It does nothing to "nudge" the garbage collector.
The whole point of having a GC is that you don't need to worry about object lifetime.
Setting a variable to null is only of value of the C# compiler can not work out it's self that it is not going to be used again.
In well writen clear code there are very few cases when the c# compiler can not track the last time a local variable is used it's self.
Now if finalResults was a field, it would be a different case.
The answers above are correct, but nobody seems to be making this distinction, so I will:
It depends on how finalResults was declared. If it's a local variable that was declared in a method, then there will be no effect at all; the object it was referencing would be eligible for garbage collection when the method goes out of scope in any case (and it will still be up to the garbage collector to figure out when it wants to clean up).
If, however, finalResults was a class field, or property, then it's a slightly different scenario (although the small "f" seems to suggest that it is not). In this case, the object it forms part of will hold a reference to the object referenced by finalResults, until it can be garbage collected itself (which happens when there's nothing holding a reference to it, in turn). In a situation like this, you may actually want to set it to null, to allow for the object to be eligible for GC earlier (assuming the referencing object is still going to be around for a significant amount of time).
Check the generated IL; you may well find that the compiler knows the variable is never referenced again, so doesn't bother to generate any code for that line, in which case you know there won't be a difference in behaviour.
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.