.NET 4.x: how to force full GC collection? - c#

It seems some update changed GC behavior when built in Debug configuration or with debugger attached:
//Code snippet 1
var a = new object();
var w = new WeakReference(a);
a = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine(w.IsAlive ? "Alive" : "Dead");
Such code used to print Dead, and it was very handy for writing unit-tests checking that certain parts that should be GCed are not being held.
After some .NET 4.x update, this code passes successfully on .NET 2.x and 3.x, but fails on all variants of 4.x. I tried to call it as GC.Collect(2, GCCollectionMode.Forced, blocking: true), making <gcConcurrent enabled="false"/> in App.config and GCSettings.LatencyMode = GCLatencyMode.Batch - nothing helps. If I run the code without debugger attached and it is built in Release configuration (i.e. with optimizations) - it outputs Dead. Otherwise it is Alive.
I understand that relying on GC is not a good idea in production. But for tests I don't know how to replace ability to check through test that particular code piece does not leak memory. It is pure test assembly, I'm fine with turning some compatibility switches, or something alike. My goal is to check my own code, not the GC optimizations.
Is there a way to force GC to previous behavior somehow?
P.S. I saw almost identical question, but at that time it was related to NCrunch. I don't have it installed. I ran the code even from command line, without VS at all, with the same results.
UPD: I found that if I move code with allocating and setting reference to null into separate method - it consistently outputs Dead, though.
//Code snippet 2
internal class Program
{
private static void Main(string[] args)
{
var w = DoWorkAndGetWeakRef();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine(w.IsAlive ? "Alive" : "Dead");
Console.ReadLine();
}
private static WeakReference DoWorkAndGetWeakRef()
{
var a = new object();
var w = new WeakReference(a);
a = null;
return w;
}
}
Same result if I move out to separate method GC collection calls and WeakReference check:
//Code snippet 3
internal class Program
{
private static void Main(string[] args)
{
var a = new object();
var w = new WeakReference(a);
a = null;
CollectAndCheckWeakRef(w);
Console.ReadLine();
}
private static void CollectAndCheckWeakRef(WeakReference w1)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine(w1.IsAlive ? "Alive" : "Dead");
}
}
The important point though as it seems is that original w variable is not in current scope. If I move Console.WriteLine(w1.IsAlive ? "Alive" : "Dead"); back to Main - it becomes Alive again.
Both variants are not very convenient sometimes, but at least consistent (Debug or Release configuration, debugger is attached or not - still outputs Dead).
Now I'm curious how mere presence of WeakReference variable in current execution scope prevents GC from cleaning its Target and why having it somewhere in scope buried in call stack doesn't do the same.

In Debug mode this is supposed to keep the object alive in all .NET versions. Anything else is a bug (or a missing feature).
You can disable this debug aid by splitting some code off to a fresh method.
In Release mode this should exhibit the short GC lifetimes that you want. That's not guaranteed of course but it's a very desirable optimization.
Another workaround would be to use a new object[1] or a similar construct. You can then null out the first array member reliably. I think the framework has a Box or StrongBox type. Not sure what it's called.

You can't really rely on IsAlive property. The problem with it, is that you can only trust it if it returns false.
Have a look at Why You Shouldn’t Rely On WeakReference.IsAlive
While a WeakReference points to an object that is either live
(reachable), or garbage (unreachable) that has not yet been collected
by the GC, the IsAlive property will return true. After an object has
been collected, if the WeakReference is short (or if the target object
does not have a finalizer) then IsAlive will return false.
Unfortunately by the time IsAlive returns, the target may have been
collected.
This situation can occur because of the way the GC
suspends all managed threads before scanning the heap for garbage and
collects it (this is an oversimplified explanation for illustrative
purposes). The GC can run at any time between two instructions.
The following way is the reliable way to check it.
object a = new object();
WeakReference wr = new WeakReference(a);
object aa = (object)wr.Target;
Console.WriteLine(aa != null ? "Alive" : "Dead");

The easiest way it seems is to make var a = new object(); a class field instead of a local variable. Makes test less isolated, but seems consistent right now and does not prevent GC from collecting in the middle of the method.

Related

Object not being garbage collected when run in x64 [duplicate]

I have a test that I expected to pass but the behavior of the Garbage Collector is not as I presumed:
[Test]
public void WeakReferenceTest2()
{
var obj = new object();
var wRef = new WeakReference(obj);
wRef.IsAlive.Should().BeTrue(); //passes
GC.Collect();
wRef.IsAlive.Should().BeTrue(); //passes
obj = null;
GC.Collect();
wRef.IsAlive.Should().BeFalse(); //fails
}
In this example the obj object should be GC'd and therefore I would expect the WeakReference.IsAlive property to return false.
It seems that because the obj variable was declared in the same scope as the GC.Collect it is not being collected. If I move the obj declaration and initialization outside of the method the test passes.
Does anyone have any technical reference documentation or explanation for this behavior?
Hit the same issue as you - my test was passing everywhere, except for under NCrunch (could be any other instrumentation in your case). Hm. Debugging with SOS revealed additional roots held on a call stack of a test method. My guess is that they were a result of code instrumentation that disabled any compiler optimizations, including those that correctly compute object reachability.
The cure here is quite simple - don't ever hold strong references from a method that does GC and tests for aliveness. This can be easily achieved with a trivial helper method. The change below made your test case pass with NCrunch, where it was originally failing.
[TestMethod]
public void WeakReferenceTest2()
{
var wRef2 = CallInItsOwnScope(() =>
{
var obj = new object();
var wRef = new WeakReference(obj);
wRef.IsAlive.Should().BeTrue(); //passes
GC.Collect();
wRef.IsAlive.Should().BeTrue(); //passes
return wRef;
});
GC.Collect();
wRef2.IsAlive.Should().BeFalse(); //used to fail, now passes
}
private T CallInItsOwnScope<T>(Func<T> getter)
{
return getter();
}
There are a few potential issues I can see:
I am unaware of anything in the C# specification which requires that the lifetimes of local variables be limited. In a non-debug build, I think the compiler would be free to omit the last assignment to obj (setting it to null) since no code path would cause the value of obj will never be used after it, but I would expect that in a non-debug build the metadata would indicate that the variable is never used after the creation of the weak reference. In a debug build, the variable should exist throughout the function scope, but the obj = null; statement should actually clear it. Nonetheless, I'm not certain that the C# spec promises that the compiler won't omit the last statement and yet still keep the variable around.
If you are using a concurrent garbage collector, it would may be that GC.Collect() triggers the immediate start of a collection, but that the collection wouldn't actually be completed before GC.Collect() returns. In this scenario, it may not be necessary to wait for all finalizers to run, and thus GC.WaitForPendingFinalizers() may be overkill, but it would probably solve the problem.
When using the standard garbage collector, I would not expect the existence of a weak reference to an object to prolong the existence of the object in the way that a finalizer would, but when using a concurrent garbage collector, it's possible that abandoned objects to which a weak reference exists get moved to a queue of objects with weak references that need to be cleaned up, and that the processing of such cleanup happens on a separate thread that runs concurrently with everything else. In such case, a call to GC.WaitForPendingFinalizers() would be necessary to achieve the desired behavior.
Note that one should generally not expect that weak references will be invalidated with any particular degree of timeliness, nor should one expect that fetching Target after IsAlive reports true will yield a non-null reference. One should use IsAlive only in cases where one wouldn't care about the target if it's still alive, but would be interested in knowing that the reference has died. For example, if one has a collection of WeakReference objects, one may wish to periodically iterate through the list and remove WeakReference objects whose target has died. One should be prepared for the possibility that WeakReferences might remain in the collection longer than would be ideally necessary; the only consequence if they do so should be a slight waste of memory and CPU time.
As far as I know, calling Collect does not guarantee that all resources are released. You are merely making a suggestion to the garbage collector.
You could try to force it to block until all objects are released by doing this:
GC.Collect(2, GCCollectionMode.Forced, true);
I expect that this might not work absolutely 100% of the time. In general, I would avoid writing any code that depends on observing the garbage collector, it is not really designed to be used in this way.
Could it be that the .Should() extension method is somehow hanging on to a reference? Or perhaps some other aspect of the test framework is causing this issue.
(I'm posting this as an answer otherwise I can't easily post the code!)
I have tried the following code, and it works as expected (Visual Studio 2012, .Net 4 build, debug and release, 32 bit and 64 bit, running on Windows 7, quad core processor):
using System;
namespace Demo
{
internal class Program
{
private static void Main(string[] args)
{
var obj = new object();
var wRef = new WeakReference(obj);
GC.Collect();
obj = null;
GC.Collect();
Console.WriteLine(wRef.IsAlive); // Prints false.
Console.ReadKey();
}
}
}
What happens when you try this code?
This answer is not related to unit tests, but it might be helpful to somebody who's testing out weak references and wondering why they don't work as expected.
The issue is basically the JIT keeping the variables alive. This can be avoided by instantiating the WeakReference and the target object in a non-inlined method:
private static MyClass _myObject = new MyClass();
static void Main(string[] args)
{
WeakReference<object> wr = CreateWeakReference();
_myObject = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
wr.TryGetTarget(out object targetObject);
Console.WriteLine(targetObject == null ? "NULL" : "It's alive!");
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static WeakReference<object> CreateWeakReference()
{
_myObject = new MyClass();
return new WeakReference<object>(_myObject);
}
public class MyClass
{
}
Commenting out _myObject = null; will prevent garbage collection of that object.
I have a feeling that you need to call GC.WaitForPendingFinalizers() as I expect that week references are updated by the finalizers thread.
I had issues with the many years ago when writing a unit test and recall that WaitForPendingFinalizers() helped, so did making to calls to GC.Collect().
The software never leaked in real life, but writing a unit test to prove that the object was not kept alive was a lot harder then I hoped. (We had bugs in the past with our cache that did keep it alive.)

c# destructors (or finalisers?) called automatically at the end of my program - should I do somthing about that?

So I have been reading loads of posts regarding how to deal with memory allocation and finalisers etc... I think I am clear on it, until I saw the debug that I get from running my program. The program itself is on a secure network and my "internet access" PC does not have C# so the un-tested example below may not give exactly the same behaviour, but hopefully serves to show what I am seeing:
I have two files:
cli.cs
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("------ ITERATION " + i + "------");
Regression.Tests.FileOperations.runTest();
}
Console.WriteLine("Test Finished");
FileOperations.cs
class FileOperations
{
Obj1 obj1 = null;
Obj2 obj2 = null;
public void doStuff()
{
// Clear the objects
obj1 = null;
obj2 = null;
// Create the objects
obj1 = new Obj1();
obj2 = new Obj2();
// do stuff (in this case just sleep for 5 seconds)
Thread.Sleep(5000);
}
// Static function so its can be called without instance
static public void runTest()
{
FileOperations fileOps = new FileOperations();
fileOps.doStuff();
}
}
So in cli.cs we call the static function runTest() in a loop which
iterates 3 times.
runTest() instantiates a FileOperations object and
then calls its doStuff() function.
doStuff() Clears any previous objects by setting them to null (I read this is the way to do that). Then it creates new instances of the objects for use.
So I tested this and it all seems to work ok. However the output to my program gives me this debug:
------ ITERATION 1 ------
------ ITERATION 2 ------
------ ITERATION 3 ------
Test Finished
~Obj1()
~Obj2()
~Obj1()
~Obj2()
~Obj1()
~Obj2()
So, if I am clearing the objects correctly (which I may not be?) why are all my Obj1 and Obj2's only getting deleted at the end of the programs? - maybe this is correct? - I have not managed to find any examples of people with the same output...
You have only three iterations, so there aren´t many point in time in your program when Garabage-Collection may take place. So even if GC would kick in three times (which I doubt in this little scenario) you could not determine if that happens before the next iteration or just after all of them. The process of GarbageCollection is quite complex and in particual un-deterministic, so you can´t determine when exactly an instance is freed from memory.
Although you have three different instances of FileOperations which hold their own instances of Obj1 and Obj2 those instances may or may not remain on the heap, until GC finally decides to kick in. This happens at least when your app terminates, but usually far earlier. The only thing you can expect from GC is that it will run. The eraliest point for the GC to work on the other side is when an instance gets out of scope and no more references to that instance exist. In your case this is when an instance of FileOperations is not used any more in your code.
So you have more or less two options in your scenario:
GC working on every iteration or at least some of them, at least far earlier then your app terminates
when your app terminates
As your program is so little chances are very high that the second option happens. As an aside this improves overall performance, as GC does not need to work - or in particular free any instances - all the time, just a few (or in your case probably one) time(s).
GC does your clean up dont use finalizer you can use finalizer when you want implement idisposable pattern to your class and override dispose method i did it here in my github repo
https://github.com/garapricot/MVCBookStore/blob/master/DAL/Services/BookService.cs

c# my destructor isn't being called?

I have this simple code and trying to call the destructor but I can't call it :(
I know that GarbageCollector runs when it's necessary, so I used GC.WaitForPendingFinalizers(); but it didn't work either.
Here is my code:
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Console.WriteLine("{0} / {1} = {2}", 120, 15, calculator.Divide(120, 15)
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Program finishing");
}
}
class Calculator
{
// Constructor
public Calculator()
{
Console.WriteLine("Calculator being created");
}
// Public Divide method
public int Divide(int first, int second)
{
return first / second;
}
// Destructor
~Calculator()
{
Console.WriteLine("Destructor is called");
}
}
And here is my output:
Calculator being created
120 / 15 = 8
Program finishing
What am I doing wrong? Why can't I see "Destructor is called" ?
The lifetime of a local variable is the lifetime of the activation of control within the local variable scope that declares it. So your local is alive until the end of main. That alone is sufficient to explain why it is not collected, but there are subtleties here that we should explore in more depth.
The lifetime may be extended by a variety of mechanisms, including capturing outer variables by a lambda, iterator blocks, asynchronous methods, and so on.
The lifetime is permitted to be shortened in cases where the jitter can prove that doing so has no effect on the single-threaded flow of control. (You can use KeepAlive to ensure this shortening does not happen in cases where you must avoid it.)
In your case, the runtime is permitted to notice that the local is never read from again, mark it as dead early, and thereby orphaning the reference to the object, which would then be collected and finalized. It is not required to do so, and apparently, in your case, does not.
As another answer correctly notes: the GC will deliberately suppress this optimization if it detects that a debugger is running, because it is a bad user experience for an object to be collected while you are examining a variable containing a reference to it in the debugger!
Let's consider the implications of my statements about shortened lifetimes, because I think you may not have fully grasped those implications.
The runtime is permitted to notice that the ctor never accesses this.
The runtime is permitted to notice that divide never accesses this.
The runtime is permitted to notice that therefore the local is never actually read from and used
Therefore the object is permitted to be never rooted in the GC at any point in its lifetime.
Which means that the garbage collector is permitted to run the finalizer before the constructor.
The GC and finalizer runs on their own threads, remember; the operating system could suspend the main thread and switch to the gc and finalizer threads at any point, including after the allocator runs but before control passes to the constructor.
Absolutely crazy things are permitted to happen in scenarios like the one you wrote; the finalizer not running is the least of your problems! It is when it could run that is scary.
If that fact was not immediately clear to you, then you have no business writing a finalizer. Writing a correct finalizer is one of the hardest things to do in C#. If you are not an expert on all the fine details of the CLR garbage collector semantics, you should not be writing a finalizer.
For more thoughts on how writing a finalizer is difficult, see my series of articles on the subject, which begins here:
https://ericlippert.com/2015/05/18/when-everything-you-know-is-wrong-part-one/
If you run a program with the debugger attached it changes the behavior of the lifetime of objects.
Without the debugger a object becomes ellagable for collection as soon as the last use of the object has been passed in the code. With the debugger attached the lifetime of all objects get extended to the entire time the object is in scope, this is done so you can view the object in the Watch window of the debugger and not have the object collected out from under you.
You must either run your program in release mode without the debugger attached or set calculator to null before you call GC.Collect() to be able to have the object be eligible for garbage collection and have it's finalizer run.
I would not recommend to really on destructors .net
anyway in your case GC don't think your object is garbage at the moment you calling GS because you have alive link in your stack calculator which is point to object in heap
so you can try to modify this code
main(){
DoCalculations();
//at this point object calculator is garbage (because it was allocated in stack)
GC.Collect();
}
DoCalculations(){
Calculator calculator = new Calculator(); // object allocated
calcualtor.doSomething(); //link alive
}

Store 'this' at finalization

How could be defined a code that store 'this' during class finalization? How the garbage collector should behave (if defined somewhere)?
In my mind the GC should finalize multiple times the class instance, and the following test application shall print "66", but the finalizer is executed only once, causing the application to print "6".
Few lines of code:
using System;
namespace Test
{
class Finalized
{
~Finalized()
{
Program.mFinalized = this;
}
public int X = 5;
}
class Program
{
public static Finalized mFinalized = null;
static void Main(string[] args)
{
Finalized asd = new Finalized();
asd.X = 6;
asd = null;
GC.Collect();
if (mFinalized != null)
Console.Write("{0}", mFinalized.X);
mFinalized = null;
GC.Collect();
if (mFinalized != null)
Console.Write("{0}", mFinalized.X);
}
}
}
What I'm trying to do is to understand how finalizers manage instance memory. In my application could be desiderable to re-use instance reference again for further processing.
It's clear that the finalizer doesn't "free" memory (at least in my test application). May the memory chunk be reused for other purposes? Or even freed? And if it isn't, that would be a memory leak or what?
Now, I'm confused more than before.
This is due to Resurrection. By storing the object in another variable during finalization (assigning this to a variable), you resurrect the obejct instance as far as the GC is concerned. You are allowed to resurrect your object in .NET, and you can actually cause the GC to finalize the object more than once, but you have to explicitly request it via GC.ReRegisterForFinalize .
For details, see Automatic Memory Management in the Microsoft .NET Framework.
GC.Collect does a sweep, special-casing any objects with a finalizer and not collecting them. Once these finalizer objects have finalized, GC then runs again over these objects. If they're no longer eligible for collection (by re-rooting, as you do), so be it. Normally the finalizer only runs once, but IIRC, you can request that it runs again.
Finalizer only gets called once. You're free to assign self to somewhere, and prevent the object being garbage collected. But once the object is available again for GC, it doesn't run the finalizer.
I'm interested in any good uses of resurrected objects.
The MSDN states "There are very few good uses of resurrection, and you really should avoid it if possible".
Also Bill Wagner in his Effective C# says "You cannot make this kind of construct work reliably. Dont try". But the book is 2 years old so maybe something changed?

Garbage collector won't collect an object created with using

I want to test for object references held improperly and wrote a test that always failed. I simplified the test to the following behaviour:
[Test]
public void ScopesAreNotLeaking()
{
WeakReference weakRef;
Stub scope = null;
using (scope = new Stub())
{
weakRef = new WeakReference(scope);
}
scope = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.That(weakRef.Target, Is.Null);
}
This test however, which does the same without using, passes:
[Test]
public void ScopesAreNotLeaking()
{
WeakReference weakRef;
Stub scope = new Stub();
weakRef = new WeakReference(scope);
scope = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.That(weakRef.Target, Is.Null);
}
The used stub class is simple enough:
class Stub : IDisposable
{
public void Dispose() {}
}
Can someone please explain me that behaviour or - even better - has an idea how to make sure that the object gets garbage collected?
PS: Bear with me if a similar question was asked before. I only examined those questions that have using in the title.
using is not designed to force garbage collection but to ensure dispose is called. Dispose allows you to release non-garbage collected resources like file handles. Garbage collection happens when c# is good and ready.
I suspect there may be a local introduced by the using statement. Use ildasm to see if all the references in the function to the object are truly cleared before the call to GC.Collect. Also try to put the using bit in a separate function that returns the weak reference.
Your two test cases are not identical. At the end of a using statement, the resource's Dispose method is called, it is not set to null. Calling Dispose does not necessarily call the destructor.
The mark & sweep GC, like it is used in .NET, is not deterministic.
Even if called by GC.Collect() there is no guarantee that is really runs.
Additionally, the using-clause does not have anything to do with garbage collection. If just calls Dispose() on its target object.

Categories

Resources