我有一些内存泄漏的麻烦。 这是我的测试代码:
// 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");
输出是:
This is a book
Book is alive
again -> This is a book
again -> Book is alive
那么,为什么“wr”在调用GC.Collect()后仍然存活? GC出了什么问题? 我在WP8& WP8.1预览。 你能帮帮我吗?
答案 0 :(得分:2)
你有一个字符串的引用,因为它是一个常量,可能是实习的,永远不会被收集:
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");
答案 1 :(得分:1)
也许是因为字符串文字存储在internal dictionary中以防止重复?有关详细信息,请参阅此处:String interning and String.Empty
尝试为您的测试分配POCO类(例如StringBuilder)而不是字符串文字。
答案 2 :(得分:0)
你永远不应该依赖GC.Collect()
来回收记忆。 .NET是一个托管环境,您可以将内存管理控制权交给运行时,以换取不必编写直接管理它的代码,并带来所有考虑因素。
调用GC.Collect()
只是告诉运行时它可能希望在下一次获得机会时运行一个收集周期 - 它不会中止一些复杂的计算,它只是在做垃圾的过程中集合。
即使这样,集合也只会发生在任何代码都无法访问的对象上,然后垃圾收集器中有三层缓存,因此在调用GC.Collect()
时期望对象立即消失错误的做事方式。
正确构建程序不需要依赖GC.Collect()
。如果实例只在需要的地方可用,那么程序的其他区域就不会出现问题。最后,如果wr
对象被垃圾回收,您拨打.IsAlive()
会产生未处理的NullReferenceException
。