【问题标题】:Why an unreferenced object is not collected?为什么不收集未引用的对象?
【发布时间】:2015-07-17 04:57:15
【问题描述】:

此程序将“True”打印到控制台。

分配一个对象,对其进行 WeakReference,超出块范围,并检查 WeakReference.IsAlive。

public static void Main (string[] args)
{
    Test ();
}

static void Test ()
{
    WeakReference wref = null;

    { // block scope
        var obj = new object ();
        wref = new WeakReference (obj);
    }

    // obj is out of scope
    // Console.WriteLine (obj);

    GC.Collect ();

    Console.WriteLine (wref.IsAlive); // => True
}

虽然 obj 超出范围,但为什么不收集 obj?

程序由Mono 3.12.0编译。

编辑:

对不起,不恰当的例子。

以下程序也打印 True。块范围似乎不相关。 这是在 Debug 模式下尝试not

    public static void Main (string[] args)
    {
        Test ();
    }

    static void Test ()
    {
        WeakReference wref = null;

        var obj = new object ();
        wref = new WeakReference (obj);
        obj = null;

        GC.Collect ();

        Console.WriteLine (wref.IsAlive); // => True
    }

$ mcs -debug- Program.cs
$ mono Program.exe

【问题讨论】:

  • 您是否尝试将“Force”作为参数传递给GC.Collect
  • Regular .Net 的行为类似 - 您需要在发布模式下编译(或“csc /debug-sample.cs”,如果使用命令行)才能实现 - Mono 的行为可能类似以简化调试.
  • @Atomosk 我尝试了“强制”,但结果相同。

标签: c# mono


【解决方案1】:

我猜是因为你是在调试器中运行的。

尝试运行发布版本,然后在调试器之外手动运行它。

【讨论】:

  • 请注意,在常规 .Net 中,区别在于是否为调试和发布配置(/debug+ 或 /debug- 编译器标志)编译可执行文件。我不认为当附加调试器时,释放 IL 会更改局部变量的生命周期,但不确定。
  • @AlexeiLevenkov 附加调试器后,JIT 编译器会以不同方式编译。事实上,C# 根本不关心块范围——不管是否在范围内,如果没有附加调试器,任何将来不会使用的本地都立即“免费收集”。附加调试器后,它会一直存在到方法的末尾。
  • 它是真的。如果你手动设置obj = null;,它也会在调试中打印出错误
  • @ luaan您是对的......确实提示当检查“抑制加载上的优化”时,对于新的JIT-ed方法也是相同的,即使是用于发布构建。如果没有调试器,我相信调试和发布版本的行为仍然会有所不同 (blogs.msdn.com/b/jaybaz_ms/archive/2004/06/28/168314.aspx) - 至少我对 OP 提供的代码的测试显示...
【解决方案2】:

您希望 GC 是 100% 确定性的,但实际上并非如此。

可能发生的一些事情:

  • JIT 优化了 null 分配。
  • 可以将指向实例的指针留在临时堆栈位置或寄存器中(在某些架构上,您调用函数,传递变量,这会将变量放入寄存器中)。

【讨论】:

    【解决方案3】:

    在 GC.Collect 之后,添加:

    GC.WaitForPendingFinalizers(); 
    

    通过调用此过程,所有可终结的对象都可以在继续您的程序之前执行任何必要的清理。它确保您的代码不会调用当前正在销毁的对象上的方法。

    【讨论】:

    • 该评论更多地是关于您是否可以在答案中添加一些信息,它有什么作用,例如
    猜你喜欢
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多