在这种情况下,.Net会调用我吗?

时间:2015-05-28 21:21:00

标签: .net f# garbage-collection idisposable

对于我在互联网上阅读的内容,您应该在不再需要的情况下随时调用IDisposable个对象处置

这个问题是关于一个特殊情况,(对我而言)显然不再需要对象,也许.Net可能会为我调用处理。

案例:

type Foo() =
    let disposable:IDisposable = // create an IDisposable
    ...

问题是:只要类型foo的{​​{1}}无法访问(垃圾收集的候选者;没有指向它的引用),Foo会被处置吗?

我的猜测是disposable一旦没有disposable的引用就不会被处置,因为实时没有引用计数(AFAIK),但可能foo被垃圾收集时.Net将处置foo

现在,我避免在那个地方制造一次性用品,因为我不清楚谁应该叫处理,即使.Net称为处置,我也不知道它会多久发生。

3 个答案:

答案 0 :(得分:4)

在这种情况下可能很明显,但除非您要求,否则无法调用.Dispose(例如,将let替换为use)。

当对象是GC:ed(它可能永远不会是非确定性和所有)时,如果对象有终结器,那么GC会将对象添加到终结器队列。

终结器线程然后可能在终结器上运行终结器,终结器可以释放非托管资源但托管资源,就像实现{{1}的其他.NET对象一样}。另外,由于它是错误的线程,因此很难在终结器中释放具有线程关联性的资源,如Windows句柄。

最后,对象可以获得GC:ed。

因此GC对于纯内存资源来说很棒(对某种类型),对于其他资源,我们通过调用IDisposable或使用Dispose来使用确定性和显式资源集合。

Eric Lippert最近在精彩的终结者世界中写了一篇有趣的blog,值得查看更多细节。

答案 1 :(得分:3)

如前所述,垃圾收集器不会直接调用Dispose,但是当disposable被垃圾收集时将调用终结器,并希望以类似的方式清理其资源。 / p>

不幸的是,将let更改为use并不能解决此问题,因为它会导致编译错误:

type Foo() =    
    use disposable:IDisposable = // create an IDisposable

// error FS0523: 'use' bindings are not permitted in primary constructors

您的选择是:

  1. disposable

    的方法中定义Foo
    type Foo() = 
        member this.DoSomething() =
            use disposable:IDisposable = // create an IDisposable
    
  2. 或者,使Foo IDisposable并将责任推给消费者

    type Foo() =        
        let disposable:IDisposable = // create an IDisposable
    
        interface IDisposable with
            member this.Dispose() = disposable.Dispose()
    
        member this.DoSomething() = ()    
    
    let bar () =
        use t = new Foo()
        t.DoSomething()
    

答案 2 :(得分:2)

以下是您需要了解的关于IDisposable的所有信息:CLR Inside Out: Digging into IDisposable

简而言之,垃圾收集器不会调用Dispose,但如果对象有终结器,则会调用终结器。所有设计良好的IDisposable实现包含非托管资源的实现都将使用与Dispose方法相同的终结器。

但是,如果等待垃圾收集器清理内存,则会出现非确定性行为,并且您的应用程序也可能以非最佳方式使用内存。 不处置一次性资源可能会对性能产生不利影响。

但是,在F#中,通常很容易确保自动处理对象:只需使用use关键字而不是let绑定。

但是,这在这个特定的例子中并不起作用,因为Foo是一个,这意味着disposable不是 ,而是一个字段。这意味着它不会超出范围,直到对象本身超出范围,但AFAIK,没有特定的语言结构来支持它(C#中也没有)。

以下是如何为Foo实现 Dispose idiom

open System

type Foo() =
    let disposable:IDisposable = // create an IDisposable
    abstract member Dispose : disposing : bool -> unit
    default this.Dispose disposing =
        if disposing then disposable.Dispose ()
    interface IDisposable with
        member this.Dispose () = 
            this.Dispose true
            GC.SuppressFinalize this

唯一不符合标准的部分'处理惯用法是虚拟的 Dispose 方法(bool -> unit)没有受到保护,因为F#不支持(AFAIK)。