【问题标题】:Strange behaviour while Unit testing for memory leak using WeakReference使用 Wea​​kReference 对内存泄漏进行单元测试时的奇怪行为
【发布时间】:2017-02-19 15:08:39
【问题描述】:

我正在尝试编写一个单元测试来测试内存泄漏。 复制步骤:

    TestClass test = new TestClass();
    WeakReference reference = new WeakReference(test, true);

    test = null;

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    Debug.Assert(reference.Target == null, "Memory Leak"); // This works

     //Replacing the above line with following, I see "Memory Leak" being printed.

    if (reference.Target != null)
    {
        Console.WriteLine("Memory Leak");
    }

我添加了一个终结器:

~TestClass() { Console.WriteLine("TestClass instance finalized");}

我注意到终结器在 Assert 案例中作为 GC 命令的一部分被调用,但是当我用 if 条件替换它时,终结器不会作为 GC 命令的一部分被调用,因此引用的目标仍然存在.终结器仅在程序存在之前被调用。

预期行为:

if(reference.Target != null) Console.WriteLine("Memory Leak");

应该可以。

实际行为:

Debug.Assert(reference.Target == null, "Memory Leak");

有效但

if(reference.Target != null) Console.WriteLine("Memory Leak");

打印“内存泄漏”时不起作用

【问题讨论】:

    标签: c# .net memory-leaks garbage-collection


    【解决方案1】:

    我找到了这个问题的根本原因。此代码将在 Release 构建配置中按预期工作,但在调试中(这是我正在运行的)。

    在 Debug 的情况下,“test”之所以没有被 GC,是因为存在一个成员“reference”,它的属性 Target 持有对“test”对象的引用。为了能够使用调试器工具(如 Watch 窗口)查看此内容,编译器会使其保持活动状态。如果您摆脱了 WeakReference 实例(以及相应的 if 条件),即使在调试模式下,您也会看到它被 GC 处理。此外,如果在 Debug.Assert 中使用了“引用”,它似乎不包含对目标的引用,并且允许“测试”被 GC'ed。

    在Release模式下,“test”被GC的原因是编译器JIT编译代码并摆脱“test”变量(因为它无论如何都分配给null)并且没有办法引用它在代码中的任何地方。这使它能够被 GC 处理。由于“reference”是对“test”对象的弱引用,它不会持有它并允许它被GC'ed,因此if条件在Release模式下有效。

    【讨论】:

      猜你喜欢
      • 2018-11-02
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-06
      相关资源
      最近更新 更多