Contents

Eric Lippert在When everything you know is wrong part onepart two中列举了一堆关于Finalizer的错误认识。

  1. 把一个变量赋值为null会调用它之前指向的对象的Finalizer。
  2. 调用一个对象的Dispose()函数会调用它的Finalizer。
  3. 调用GC.Collect()会调用Finalizer。
  4. 只要一个对象有Finalizer,Finalizer就一定会被调到。
  5. 只要一个对象有Finalizer,并且没有调过SuppressFinalize,Finalizer就一定会被调到。
  6. 没有被任何对象引用的对象的Finalizer就一定会被调到。
  7. 如果一个对象被GC认为没有被任何对象引用,它的Finalizer就一定会被调到。
  8. 如果对象已经被放到了finalized queue,并且finalize线程已经被调度了,那它的Finalizer就一定会被调到。
  9. 如果对象已经被放到了finalized queue,并且finalize线程已经被调度了,并且finalizer都运行的很快,而且没有抛出异常,那它的Finalizer就一定会被调到。
  10. 局部变量只有在出了作用域它的Finalizer才可能会被调到。关于这个,可以参见我的博文谁动了我的timer?C#的垃圾回收和调试
  11. Finalizer不可能被调用多次。看看这个API:GC.ReRegisterForFinalize
  12. 被调到Finalizer的对象是死对象。
  13. 被调到Finalizer的对象是不能被别的对象在指到的。
  14. 运行Finalizer的线程就是创建这个对象的线程。通常都在Finalize线程释放,但是COM的STA对象必须在STA线程释放,这个可以参见我的博文如何判断C#的Finalizer线程有没有被阻塞
  15. 运行Finalizer的线程就是GC线程。
  16. GC判断一个对象是死对象时就会调用它的Finalizer。
  17. Finalizer从来不会死锁。
  18. Fianlizer的运行顺序是可以预计的。
  19. 一个被调到Finalizer的对象可以安全访问其它对象。
  20. 运行Finalizer会释放内存。
  21. 被调到Finalizer的对象肯定是完全创建好的对象。

再次强调一下,上面列举的这些都是错误的。Finalizer的坑这么多,那就还是不要用了。

Contents