WeakReference wrapping a string causes strange behavior
I know that I should only use WeakReference for large objects, but I'm wondering what the following scenario looks like:
object obj = 1; //Int32
var wk = new WeakReference(obj);
Console.WriteLine(wk.IsAlive); //Prints: True
obj = null;
GC.Collect(2, GCCollectionMode.Forced, true);
Console.WriteLine(wk.IsAlive); //Prints: false, All Rigth!
So far so good.
Take a look:
object obj = "test"; //String
var wk = new WeakReference(obj);
Console.WriteLine(wk.IsAlive); //Prints: True
obj = null;
GC.Collect(2, GCCollectionMode.Forced, true);
Console.WriteLine(wk.IsAlive); //Prints: True, Why?
what's happening?
source to share
From comments String.Intern
:
The common language framework preserves string storage by maintaining a table called a cross-domain pool, which contains a single reference to each unique literal string that is declared or created programmatically in your program. Therefore, an instance of a literal string with a specific value exists only once in the system.
So there is another link that you cannot release programmatically. Changing the code a little to generate an instance at runtime gives the expected result:
object obj = new string(new char[] { 't', 'e', 's', 't' });
var wk = new WeakReference(obj);
Console.WriteLine(wk.IsAlive); //Prints: True
obj = null;
GC.Collect(2, GCCollectionMode.Forced, true);
Console.WriteLine(wk.IsAlive); //Prints: False
source to share
A string is a compile-time literal, so unless you turn off automatic compile-time literal interpolation when your code is compiled (it will be enabled by default), all compile-time literal strings will be stored in a lookup table, preventing them from being GCed throughout their lifetime applications.
source to share