【问题标题】:GarbageCollector nullifying member fields?GarbageCollector 使成员字段无效?
【发布时间】:2011-09-20 22:32:02
【问题描述】:

我正在调试一些实现了 Dispose-Finalize 模式的 C# 类(比方说 Foo),即它的 Finalizer 正在调用 Dispose(),以防 Dispose 尚未被调用。

在 Dispose() 中有访问 Foo 的某些成员(比方说 Bar)的日志记录代码。 Bar 也是一些引用类型的实例,是只读的(在 Foo 的构造函数中创建)并且不会暴露在 Foo 之外的任何地方。因此,在 Foo 的垃圾回收时,Bar 很可能已经被回收了。该理论认为不应从 Finalize 线程访问此类成员字段。

但日志代码不了解理论,并试图记录 Bar 的一些属性。并且进程在 Finalizer 的线程中因 NullReferenceException 而崩溃。

我知道当您忽略该理论时可能会发生坏事,但我没想到 NRE:垃圾收集器是否将对收集的对象的引用设置为空?还是我错过了什么?

【问题讨论】:

  • 我不知道它是否真的将它设置为null,但是如果它的内存已被回收,你就无法访问一个对象,所以它必须做一些事情,或者抛出一些错误。

标签: c# .net garbage-collection clr


【解决方案1】:

Implementing a Dispose Method 中,他们特别注意从终结器访问其他对象。这就是他们有这种模式的原因:

~MyObject()
{
    Dispose(false);  // False because it's being called in a finalizer
}

public void Dispose()
{
    Dispose(true);  // True because it was called from user code
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        // here it's safe to access other CLR objects
    }

    // Here you dispose of any unmanaged objects
}

如果你偏离了这个模式——特别是如果终结器调用Dispose 并尝试访问可能已经被释放的其他对象,你就会遇到问题。

还请注意,除非您正在创建一个分配非托管资源的类,否则您不需要终结器。如果您的类仅使用 CLR 对象或提供 .NET 对象的第三方库,则不需要终结器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-17
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 2013-06-27
    • 2014-11-07
    • 1970-01-01
    相关资源
    最近更新 更多