bl4ck
bl4ck

Reputation: 1

WP8 - GC.Collect() don't work

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

Answers (3)

DmitryG
DmitryG

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

dyson
dyson

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

dbc
dbc

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

Related Questions