Reputation: 1
I have some troubles with memory leak. Here's my test code:
// Create the object
string book = "This is a book";
Debug.WriteLine(book);
// Set weak reference
WeakReference wr = new WeakReference(book);
// Remove any reference to the book by making it null
book = null;
if (wr.IsAlive)
{
Debug.WriteLine("Book is alive");
var book2 = wr.Target as string;
Debug.WriteLine("again -> " + book2);
book2 = null;
}
else
Debug.WriteLine("Book is dead");
// Lets see what happens after GC
GC.Collect();
GC.WaitForPendingFinalizers();
// Should not be alive
if (wr.IsAlive)
Debug.WriteLine("again -> Book is alive");
else
Debug.WriteLine("again -> Book is dead");
And output is:
This is a book
Book is alive
again -> This is a book
again -> Book is alive
So, why "wr" still alive after call GC.Collect()? Anything wrong with GC? I'm run on WP8 & WP8.1 preview. Can you help me.
Upvotes: 0
Views: 234
Reputation: 17850
You have a reference to a string, which since it is a constant, is probably interned and will never be collected:
string strBook = wr.Target as string;
if(strBook != null) {
Console.WriteLine("again -> Book is alive");
if(string.IsInterned(strBook) != null)
Debug.WriteLine("Because this string is interned");
}
else Console.WriteLine("again -> Book is dead");
Upvotes: 2
Reputation: 886
You should never rely on GC.Collect()
to reclaim the memory. .NET is a managed environment, you give control of memory management to the runtime in exchange for not having to write code that manages it directly, with all the considerations that brings.
Calling GC.Collect()
simply advises the runtime that it may wish to run a collection cycle when it next gets the opportunity - it is not going to abort some complex computation that it is in the middle of simply to do a garbage collection.
Even then, collection will only occur on objects that are no longer reachable by any code, and then there are three tiers of cache within the garbage collector, so expecting objects to instantly disappear when GC.Collect()
is called is the wrong way to go about things.
Structuring your program correctly should remove the need to rely on GC.Collect()
. If instances are only available where they are required, you will not have problems with other areas of the program interfering with them. Finally, had the wr
object been garbage collected, you call to .IsAlive()
would have produced an unhandled NullReferenceException
.
Upvotes: 0
Reputation: 116680
Perhaps it's because string literals are stored in an internal dictionary to prevent duplication? See here for details: String interning and String.Empty
Try allocating a POCO class (e.g. a StringBuilder) instead of a string literal for your test.
Upvotes: 1