Memory leak when ThreadLocal<T> is used in cyclic graph - c#

I just came across this weird 'behavior' of the Garbage Collector concerning System.Threading.ThreadLocal<T> that I can't explain. In normal circumstances, ThreadLocal<T> instances will be garbage collected when they go out of scope, even if they aren't disposed properly, except in the situation where they are part of a cyclic object graph.
The following example demonstrates the problem:
public class Program
{
public class B { public A A; }
public class A { public ThreadLocal<B> LocalB; }
private static List<WeakReference> references = new List<WeakReference>();
static void Main(string[] args) {
for (var i = 0; i < 1000; i++)
CreateGraph();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
// Expecting to print 0, but it prints 1000
Console.WriteLine(references.Count(c => c.IsAlive));
}
static void CreateGraph() {
var a = new A { LocalB = new ThreadLocal<B>() };
a.LocalB.Value = new B { A = a };
references.Add(new WeakReference(a));
// If either one of the following lines is uncommented, the cyclic
// graph is broken, and the programs output will become 0.
// a.LocalB = null;
// a.LocalB.Value = null;
// a.LocalB.Value.A = null;
// a.LocalB.Dispose();
}
}
Although not calling Dispose is not good practice, but it's the CLR's design to clean up resources (by calling the finalizer) eventually, even if Dispose is not called.
Why does ThreadLocal behave differently in this regard and can cause memory leaks when not disposed properly in case of a cyclic graph? Is this by design? And if so, where is this documented? Or is this a bug in the CLR's GC?
(Tested under .NET 4.5).

Microsoft's David Kean confirmed that this actually is a bug.

The reason is that you're not calling Dispose. The garbage collector will only clean up objects that have finalizers as a last resort.

Related

C# Finalizer not freeing unmanaged memory

I have a MappedMemory class that allocates a chunk of memory via Marshal.AllocHGlobal(). The class implements IDisposable, and I have it set up to auto-dispose the allocated memory when the class is finalized. However, it does not appear to be working as intended.
class MappedMemory : IDisposable
{
private bool disposed_ = false;
private IntPtr memoryPtr_;
public MappedMemory( int capacity )
{
memoryPtr_ = Marshal.AllocHGlobal( capacity );
}
~MappedMemory()
{
Dispose( false );
}
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
protected virtual void Dispose( bool disposing )
{
if ( !disposed_ )
{
if ( disposing )
{
// Clear managed resources
}
Marshal.FreeHGlobal( memoryPtr_ );
}
disposed_ = true;
}
}
I have written two tests to ensure that the memory is being freed properly:
public MappedMemory_finalizer_frees_memory()
{
for( var i = 0; i < 1e8; i++ )
{
var memory = new MappedMemory( 128 );
}
}
public MappedMemory_dispose_frees_memory()
{
for( var i = 0; i < 1e8; i++ )
{
var memory = new MappedMemory( 128 );
memory.Dispose();
}
}
When the tests are run, the test that manually calls Dispose() works as it should, and memory stays at a constant utilization.
The test for the finalizer, however, does not appear to be freeing the allocated memory, and it leaks out of control until it runs out of memory. I have set a breakpoint and the call to Marshal.FreeHGlobal( memoryPtr_ ) is hit.
Manually adding GC.Collect() to the test fixes the problem, so ultimately it appears that the memory is deallocated, but not garbage collected?
I am super confused as to what is happening here. Can someone explain why the finalizer does not free the memory, and how I can ensure that it does in production?
From the MSDN documentation here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors
The programmer has no control over when the finalizer is called
because this is determined by the garbage collector. The garbage
collector checks for objects that are no longer being used by the
application. If it considers an object eligible for finalization, it
calls the finalizer (if any) and reclaims the memory used to store the
object.
As you say that forcing garbage collection frees the memory I suspect that the issue you're seeing is that there isn't enough pressure on the memory systems to cause garbage collection to run automatically. Garbage collection is a relatively expensive process so it is not run unless there is a reason to do so.

when object goes out of scope in c #?

Method where scopes defined explicitly.
static void Main(string[] args)
{
Class1 c1 = new Class1(1);
{
Class1 c2 = new Class1(2);
{
Class1 c3 = new Class1(3);
}
//this is not collecting object c3 which is out of scope here
GC.Collect();
}
//this is not collecting object c2 which is out of scope here
GC.Collect();
Console.ReadKey();
}
Class1 definition:
class Class1
{
int x;
public Class1(int a)
{
x = a;
}
~Class1()
{
Console.WriteLine(x + "object destroy");
}
}
I write this code. But GC.Collect() method don't collect the object which goes out of scope.
GC.Collect() isn't really meant to be used for deterministic reclamation of resources. (That is what your finalizers in your real code is doing, right?)
If you have an unmanaged resource to deal with, strong consider using one of the classes in Microsoft.Win32.SafeHandles.
If you want deterministic release of resources, you should implement IDisposable, and call Dispose() when you are done using the object. The idiomatic way of doing this is:
using (var someResource = new Class1(1))
{
// work with the `Class1` object
}
which is functionally equivalent to
{
var someResource = new Class1(1);
try
{
// work with the `Class1` object
}
finally
{
someResource.Dispose();
}
}
What you think about scoping is correct. Objects are going out of scope exactly as you expect. However, apparently the way you are testing it is not so correct.
Couple of points to consider here.
You should implement the finalizer only if you have any unmanaged resources.
If your class has a finalizer and if you don’t implement IDisposable Correctly in a way that it the suppress the finalization, instances of that class can reside in memory for two garbage collection cycles. Because, the first GC.Collect add that instance to the finalization queue if it requires finalization. May be the second garbage collection cycle actually clears the memory.
Finalizer is the last point where .net objects can release unmanaged resources.
Finalizers are to be executed only if you don’t dispose your instances correctly. Ideally, finalizers should never be executed. Because proper dispose implementation should suppress the finalization.
According to your sample code, if you call GC.Collect and WaitForPendingFinalizers your test may pass (not sure how to find if memory is cleared).
Better test for you.
Garbage collector doesn't take inner scopes into account when clearing memory. If you move your code into a separate method it executes the finalizer.
Test 1
static void Main(string[] args)
{
GCTest();
Console.ReadKey();
}
private static void GCTest()
{
Class1 c1 = new Class1(1);
{
Class1 c2 = new Class1(2);
{
Class1 c3 = new Class1(3);
}
//this is not collecting object c3 which is out of scope here
GC.Collect();
GC.WaitForPendingFinalizers();
}
//this is not collecting object c2 which is out of scope here
GC.Collect();
GC.WaitForPendingFinalizers();
}
Test 2
Use using statement if you want to specify scoping for garbage collection purposes.
private static void Main(string[] args)
{
using (Class1 c1 = new Class1(1))
{
using (Class1 c2 = new Class1(2))
{
Class1 c3 = new Class1(3);
}
}
Console.ReadKey();
}
class Class1 : IDisposable
{
int x;
public Class1(int a)
{
x = a;
}
public void Dispose()
{
Console.WriteLine(x + "object disposing");
}
}
Output
2object disposing
1object disposing
Theses scopes do not make it into IL. The runtime has no idea they were there. At the IL level there are just locals and stack contents. Although the .NET JIT is poor in general it does a decent job of optimizing locals and temporary values into an efficient form.
There are no guarantees when objects will be collected. GC.Collect can't force that. There are some safe patterns to have it 99.999% guaranteed but never fully.
You never need this facility. In fact the need to have a finalizer is almost zero. Use the SafeHandle infrastructure.
If you really want to see the effect, move all of this code into a helper method and call that from Main. Back in main the Collect will succeed.

Destroy target of WeakReference

I'm writing a small MemoryManager for my WPF application and reached the following problem.
What i do: I store a lot of instances as a WeakReference in a IList<WeakReference>. Later, when i want to free all memory, i want to destroy all alive objects in the list.
To do this, i try to get the reference to the object, like this:
foreach (WeakReference wr in references)
{
if (wr.IsAlive == true)
{
if(wr.Target != null)
{
TypedReference tf = __makeref(wr.Target);
}
}
}
But i dont't know how to destroy tf. I tried to use __refval, but it does not work for me.
Sample:
InstanceDestructManager idm = new InstanceDestructManager();
IList<string> test = new List<string>();
test.Add("123");
idm.AddNullable<IList<string>>(ref test);
idm.Dispose();
// Should not be possible, because after idm.Dispose "test" should be null
test.Add("456");
General code for:
public static void Test(ref object pa)
{
pa = null;
}
Maybe some one has an idea, thank you!
Setting the WeakReference.Target to null will release the reference to it. There is no such thing as destroy memory in C#. The GC collect memory when there are no references to it. And even then it decides on its own when to free them. GC.Collect forces this. But this is not for production purposes unless you know what you're doing.

C# Destructor not working as expected

Please see the code below. I expect it to print either 10 because I have explicitly invoked the garbage collector. But I always get either a 0 or 20 as output. Why is that?
void Main()
{
Panda[] forest_panda = new Panda[10];
for(int i=0; i<forest_panda.GetLength(0);i++)
{
forest_panda[i]=new Panda("P1");
}
for(int i=0; i<forest_panda.GetLength(0);i++)
{
forest_panda[i]=new Panda("P1");
}
System.GC.Collect();
Console.WriteLine("Total Pandas created is {0}",Panda.population);
}
class Panda
{
public static int population=0;
public string name;
public Panda(string name)
{
this.name = name;
population = population + 1;
}
~Panda()
{
population = population - 1;
}
}
Please note that the class for Main is automatically created by LINQPad (the editor that comes with the "C# 4.0 in a Nutshell" book). I am new to C#.
You have not run an explict garbage collection. From the docs of GC.Collect():
Use this method to attempt to reclaim
all memory that is inaccessible.
However, the Collect method does not
guarantee that all inaccessible memory
is reclaimed.
All objects, regardless of how long
they have been in memory, are
considered for collection; however,
objects that are referenced in managed
code are not collected. Use this
method to force the system to attempt
to reclaim the maximum amount of
available memory.
The garabage collector is highly optimized and "decides" all by himself when he actually does the garbage collection and then call the finalizers. Additionally it is all done asynchronously. That is also why Finalizers are called non-deterministic cleanup. You never now when cleanup happens.
You have two options now. You can either call GC.WaitForPendingFinalizers() wich will halt the current thread until the all finalizable objects have been finalized. Or call this new overload: System.GC.Collect(int generation, System.GCCollectionMode mode) with GCCollectionMode.Forced It was introduced in .NET 3.5.
Just keep in mind that usually it is not necessary and more importantly: a bad idea to call the garbage collector manually. Also implementing the finalizer is only needed in rare occasions. Calling the garbage collector will slow down the runtime. Implementing finalizers will slow down the runtime additionally. The garabge collector puts all objects that implement the finalizer into the finalization queue when they are ready to be garabge collected. Processing this queue is expensive.
To make things worse, when the finalizer is run, it is not guaranteed that the members you are trying to access there are still alive. It is very well possible they have already been grabage collected. That's why you should use the finalizer only when you have unmanaged resources that need to be cleaned up.
All this is definately not needed in your example. What you acutally want is IDisposable for deterministic cleanup.
There are a couple of things to notice here:
First of all the GC behaves differently between release and debug builds. Generally, in release mode objects can be reclaimed sooner than in debug mode.
As Tim points out calling GC.Collect doesn't call finalizers. If you want to wait for finalizers to run call GC.WaitForPendingFinalizers as well.
Finalizers are run by a dedicated thread, so you're actually modifying state from two different threads without any synchronization. While this may not be a problem in this particular case, doing so is not a good idea. But before you go and add synchronization to your finalizer, please keep in mind that a deadlocked finalizer means that no more finalizers will run and thus the memory for those objects will not be reclaimed.
Try adding System.GC.WaitForPendingFinalizers after you garbage collect.
http://www.developer.com/net/csharp/article.php/3343191/C-Tip-Forcing-Garbage-Collection-in-NET.htm
You create twenty objects, so the value would then be 20. Explicitly calling System.GC.Collect() does not actually guarantee calling the destructor. Therefore if it was called all 20 objects may have been destructed or none may have been.
This explains what is actually happening.
It isn't good practice to create a destructor or call GC.Collect explicitly.
If An object needs to do cleanup, it should implement IDisposable
In .NET, object lifetimes are non-deterministic and do not behave as you'd expect from C++ constructor/destructors. In fact, .NET objects do not technically have destructors. The finalizer differs in that it is expected to clean up unmanaged resources used by the object during it's lifetime.
To have a deterministic way of freeing resources used by your object, you implement the IDisposable interface. IDisposable isn't perfect though as it still requires the calling code to correctly dispose of the object when it's done, and it's hard to handle accidental multiple calls to Dispose. However syntax in C# makes this generally very easy.
class Panda : IDisposable
{
public static int population = 0;
public string _name;
public Panda( string name )
{
if( name == null )
throw new ArgumentNullException( name );
_name = name;
population++;
}
protected virtual void Dispose( bool disposing )
{
if( disposing && name != null )
{
population--;
name = null;
}
}
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
~Panda(){ Dispose( false ); }
}
Then to use the class:
using( var panda = new Panda( "Cute & Cuddly" ) )
{
// Do something with the panda
} // panda.Dispose() called automatically
Using destructors (a.k.a. finalizers) is not really a good way of doing things in C#. There is no guarantee that the finalizer will ever run, even if you explicitly invoke the garbage collector. You shouldn't try to force garbage collection either, because it will probably have a negative perfomance impact on your application overall.
Instead, if you need to explicitly free resources owned by an object, you should implement the IDisposable interface, and place your cleanup logic inside the Dispose() method. Conversely, when you use an object that implements IDisposable, you should always take care to call its Dispose() method when you are finished with it. C# provides the "using" statement for this purpose.
Many classes that do I/O (such as Streams) implement IDisposable. Here is an example of using a FileStream to read a text file. Note the "using" statement to ensure the FileStream is disposed when we are finished with it:
using (FileStream fs = File.OpenRead("C:\\temp\\myfile.txt"))
{
// Read a text file 1024 bytes at a time and write it to the console
byte[] b = new byte[1024];
while (fs.Read(b, 0, b.Length) > 0)
{
Console.WriteLine(Encoding.UTF8.GetString(b));
}
} // Dispose() is called automatically here
The above code is equivalent to this:
FileStream fs = File.OpenRead("C:\\temp\\myfile.txt"))
try
{
// Read a text file 1024 bytes at a time and write it to the console
byte[] b = new byte[1024];
while (fs.Read(b, 0, b.Length) > 0)
{
Console.WriteLine(Encoding.UTF8.GetString(b));
}
}
finally
{
fs.Dispose();
}
The Disposing Pattern would be the best to use.
Here's the full implementation of your work.
Remember, that you have to call Dispose by your own like done in the code below.
public static void Main()
{
Panda[] forest_panda = new Panda[10];
for (int i = 0; i < forest_panda.GetLength(0); i++)
forest_panda[i] = new Panda("P1");
// Dispose the pandas by your own
foreach (var panda in forest_panda)
panda.Dispose();
for (int i = 0; i < forest_panda.GetLength(0); i++)
forest_panda[i] = new Panda("P1");
// Dispose the pandas by your own
foreach (var panda in forest_panda)
panda.Dispose();
Console.WriteLine("Total Pandas created is {0}", Panda.population);
}
class Panda : IDisposable
{
public static int population = 0;
public string name;
public Panda(string name)
{
this.name = name;
population = population + 1;
}
~Panda()
{
Dispose(false);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
population = population - 1;
}
}
}
It invoked for me in release build . However behaved differently in debug.

How can I write a unit test to determine whether an object can be garbage collected?

In relation to my previous question, I need to check whether a component that will be instantiated by Castle Windsor, can be garbage collected after my code has finished using it. I have tried the suggestion in the answers from the previous question, but it does not seem to work as expected, at least for my code. So I would like to write a unit test that tests whether a specific object instance can be garbage collected after some of my code has run.
Is that possible to do in a reliable way ?
EDIT
I currently have the following test based on Paul Stovell's answer, which succeeds:
[TestMethod]
public void ReleaseTest()
{
WindsorContainer container = new WindsorContainer();
container.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
container.AddComponentWithLifestyle<ReleaseTester>(LifestyleType.Transient);
Assert.AreEqual(0, ReleaseTester.refCount);
var weakRef = new WeakReference(container.Resolve<ReleaseTester>());
Assert.AreEqual(1, ReleaseTester.refCount);
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.AreEqual(0, ReleaseTester.refCount, "Component not released");
}
private class ReleaseTester
{
public static int refCount = 0;
public ReleaseTester()
{
refCount++;
}
~ReleaseTester()
{
refCount--;
}
}
Am I right assuming that, based on the test above, I can conclude that Windsor will not leak memory when using the NoTrackingReleasePolicy ?
This is what I normally do:
[Test]
public void MyTest()
{
WeakReference reference;
new Action(() =>
{
var service = new Service();
// Do things with service that might cause a memory leak...
reference = new WeakReference(service, true);
})();
// Service should have gone out of scope about now,
// so the garbage collector can clean it up
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsNull(reference.Target);
}
NB: There are very, very few times where you should call GC.Collect() in a production application. But testing for leaks is one example of where it's appropriate.
Perhaps you could hold a WeakReference to it and then check to see that it no longer alive (i.e., !IsAlive) after the tests have completed.
Based on Paul's answer, I created a more reusable Assert method. Since string's are copied by value I added an explicit check for them. They can be collected by the garbage collector.
public static void IsGarbageCollected<TObject>( ref TObject #object )
where TObject : class
{
Action<TObject> emptyAction = o => { };
IsGarbageCollected( ref #object, emptyAction );
}
public static void IsGarbageCollected<TObject>(
ref TObject #object,
Action<TObject> useObject )
where TObject : class
{
if ( typeof( TObject ) == typeof( string ) )
{
// Strings are copied by value, and don't leak anyhow.
return;
}
int generation = GC.GetGeneration( #object );
useObject( #object );
WeakReference reference = new WeakReference( #object, true );
#object = null;
// The object should have gone out of scope about now,
// so the garbage collector can clean it up.
GC.Collect( generation, GCCollectionMode.Forced );
GC.WaitForPendingFinalizers();
Assert.IsNull( reference.Target );
}
The following unit tests show the function is working in some common scenarios.
[TestMethod]
public void IsGarbageCollectedTest()
{
// Empty object without any references which are held.
object empty = new object();
AssertHelper.IsGarbageCollected( ref empty );
// Strings are copied by value, but are collectable!
string #string = "";
AssertHelper.IsGarbageCollected( ref #string );
// Keep reference around.
object hookedEvent = new object();
#pragma warning disable 168
object referenceCopy = hookedEvent;
#pragma warning restore 168
AssertHelper.ThrowsException<AssertFailedException>(
() => AssertHelper.IsGarbageCollected( ref hookedEvent ) );
GC.KeepAlive( referenceCopy );
// Still attached as event.
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber( publisher );
AssertHelper.ThrowsException<AssertFailedException>(
() => AssertHelper.IsGarbageCollected( ref subscriber ) );
GC.KeepAlive( publisher );
}
Due to differences when using the Release configuration (I assume compiler optimizations), some of these unit tests would fail if GC.KeepAlive() were not to be called.
Complete source code (including some of the helper methods used) can be found in my library.
Use dotMemory Unit framework (it's free)
[TestMethod]
public void ReleaseTest()
{
// arrange
WindsorContainer container = new WindsorContainer();
container.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
container.AddComponentWithLifestyle<ReleaseTester>(LifestyleType.Transient);
var target = container.Resolve<ReleaseTester>()
// act
target = null;
// assert
dotMemory.Check(memory =>
Assert.AreEqual(
0,
memory.GetObjects(where => where.Type.Is<ReleaseTester>().ObjectsCount,
"Component not released");
}
This is not an answer, however you may want to try running your code in both Debug and Release modes (for comparison sake).
In my experience the Debug version of JIT'ed code is made easier to debug and thus may see references stay alive longer (I belive function scope) However, code JITed in Release mode may have the objects ready for collection quickly once it is out of scope and if a Collection happens.
Also not answering your question: :-)
I would be interested in seeing you debug this code using Visual Studio in Interop mode (Managed and Native) and then breaking after displaying a message box or something. Then you can open the Debug->Windows-Immediate and then type
load sos
(Change to thread 0)
!dso
!do <object>
!gcroot <object> (and look for any roots)
(or you can use Windbg as other's have posted in previous posts)
Thanks,
Aaron

Categories