【问题标题】:WP8 - GC.Collect() don't workWP8 - GC.Collect() 不起作用
【发布时间】:2014-07-23 08:17:39
【问题描述】:

我遇到了一些内存泄漏问题。 这是我的测试代码:

// 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

那么,为什么在调用 GC.Collect() 之后“wr”仍然存在? GC有什么问题吗? 我在 WP8 和 WP8.1 预览版上运行。 你能帮帮我吗?

【问题讨论】:

    标签: c# windows-phone-8 memory-leaks garbage-collection


    【解决方案1】:

    你有一个字符串的引用,因为它是一个常量,所以它可能是被保留的并且永远不会被收集:

    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");
    

    【讨论】:

    • 有关于这种行为的文档吗?
    • @Alberto 相信你可以从阅读String.IsInterned方法参考文章的备注部分开始
    • @DmitryG 但我在收集之前将其设置为空:“book = null;”
    • @bl4ck 是的,你已经删除了这个具体的 GC-root 引用,但是所有的 interned 字符串都以 GC-root 为特殊的“intern-pool”,这一事实阻止了所有这些字符串的收集。另一个注意事项 - 在编译时已知的所有字符串都可能被保留......
    【解决方案2】:

    也许是因为字符串文字存储在internal dictionary 中以防止重复?详情见这里:String interning and String.Empty

    尝试为您的测试分配 POCO 类(例如 StringBuilder)而不是字符串文字。

    【讨论】:

      【解决方案3】:

      您永远不应该依赖GC.Collect() 来回收内存。 .NET 是一个托管环境,您将内存管理的控制权交给运行时,以换取不必编写直接管理它的代码,并考虑所有相关因素。

      调用GC.Collect() 只是告诉运行时它可能希望在下一次有机会时运行一个收集周期——它不会中止一些复杂的计算,它只是在进行垃圾收集。

      即便如此,收集只会发生在任何代码都无法访问的对象上,然后垃圾收集器内部有三层缓存,因此期望在调用GC.Collect()时对象立即消失是错误的方式去做一些事情。

      正确构建程序应该消除对GC.Collect() 的依赖。如果实例仅在需要的地方可用,则程序的其他区域干扰它们不会有问题。最后,如果wr 对象被垃圾回收,您调用.IsAlive() 将产生一个未处理的NullReferenceException

      【讨论】:

      • 请注意MSDN doc 表示GC.Collect 强制立即 垃圾回收。这不仅仅是一个迹象。
      • this question and its answers and cmets 中有类似的讨论。
      • 您链接的问题的最高投票答案是错误的,除非有人找到关于此的准确文档证明并非如此。根据规范所说,它强制立即收集。
      • 很明显,要么是文档错误,要么是 .NET Framework 中方法的实现,因为上面的示例中没有即时集合。垃圾收集在正常优先级线程上运行,因此无法保证立即运行。
      • 这个答案不是报告行为发生的原因。 “尝试为您的测试分配一个 POCO 类(例如 StringBuilder)而不是字符串文字。”
      猜你喜欢
      • 2015-11-07
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多