﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2021 (c) 2026</copyright><ttl>60</ttl><item><title>wekempf commented on Some finalizer pitfalls</title><description>There's a reason you shouldn't touch a managed object in the finalizer.  That object may have already been finalized, since the order in which objects are finalized is undefined.  The suggested code that checks for null in the finalizer may work for you during development and testing, but crash and burn spectacularly when released into the wild.  Follow the IDisposable pattern, and all will be well.
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment15</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment15</guid><pubDate>Fri, 01 Aug 2008 18:45:28 GMT</pubDate></item><item><title>Konstantin Spirin commented on Some finalizer pitfalls</title><description>AppDomain.CurrentDomain.UnhandledException += LogUnhandledException;
  
  
could significantly simplify your debugging.
  
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment14</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment14</guid><pubDate>Wed, 30 Jul 2008 16:15:57 GMT</pubDate></item><item><title>Changhong commented on Some finalizer pitfalls</title><description>oops, sorry about the wrong link.
  
Here is the right one:
  
http://www.bluebytesoftware.com/blog/2005/04/08/DGUpdateDisposeFinalizationAndResourceManagement.aspx
  
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment13</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment13</guid><pubDate>Tue, 29 Jul 2008 22:38:23 GMT</pubDate></item><item><title>Changhong commented on Some finalizer pitfalls</title><description>Patrik, you are absolutely right. A finalizer should be use for releasing unmanaged resource only. 
  
  
I remember a couple of years ago, I had a struggling with finalizer/Idisposeble, and I wanted to know how to implement a finalizer properly. But since I understood it, I never find a chance to implement it. So, I can hardly remember how to do it now.  And I have seen quite a few times other developers implemented it, which none of them were necessary.
  
  
I found this post: http://ayende.com/Blog/archive/2008/07/28/Some-finalizer-pitfalls.aspx
  
 from Joe Duffy tells me pretty much everything I want to know about finalizer/IDisposabe, and it does contain some comments on the Ayende’s issue:
  
  
“If a constructor throws an exception, the CLR will still call the object's Finalize method. So, when your Finalize method is called, the object's fields may not have all been initialized; your Finalize method should be robust enough to handle this.”
  
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment12</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment12</guid><pubDate>Tue, 29 Jul 2008 13:02:45 GMT</pubDate></item><item><title>passing by commented on Some finalizer pitfalls</title><description>Patrik Akselsson is right
  
In the finalizer you should *NOT* call fs.Dispose. The FileStream object (if it was instanciated, of course) will call its own finalizer to clean up.
  
  
You should look up the correct IDisposable pattern in MSDN.
  
  
I think simply removing the finalizer from your example makes your example work. But indeed, you can still have trouble if you try this:
  
  
BadClass bc;
  
try { bc = new BadClass(); } 
  
finally { bc.Dispose(); }
  
  
(Note that the allocation is outside the try block if you use the "using" statement.)
  
  
That's why I always check for null in my Dipose method:
  
if (fs != null) { fs.Dispose(); fs = null; }
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment11</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment11</guid><pubDate>Tue, 29 Jul 2008 09:55:04 GMT</pubDate></item><item><title>Patrik Akselsson commented on Some finalizer pitfalls</title><description>A bit off topic, but do you really need to dispose the FileStream during finalization? 
  
  
I was under the impression that you only need to make sure that unmanaged resources are released after finalization, whereas managed resources will be taken care of by the GC.  The FileStream should release it's file handle during finalization, assuming that it is well behaved. 
  
  
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment10</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment10</guid><pubDate>Tue, 29 Jul 2008 08:10:18 GMT</pubDate></item><item><title>Ayende Rahien commented on Some finalizer pitfalls</title><description>Cory,
  
That is the expected behavior, I would be surprised to learn otherwise
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment9</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment9</guid><pubDate>Mon, 28 Jul 2008 22:15:25 GMT</pubDate></item><item><title>Cory Foy commented on Some finalizer pitfalls</title><description>I tried it out with Server GC, and it didn't make a difference. I've emailed some people to see if I'm just crazy.
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment8</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment8</guid><pubDate>Mon, 28 Jul 2008 21:30:24 GMT</pubDate></item><item><title>Cory Foy commented on Some finalizer pitfalls</title><description>Hahaha! Haha! Ha..Oh. [Smacks head]
  
  
It's interesting, because the docs I have say that if an unhandled exception occurs on the finalizer thread, then only the finalization of the object is terminated.
  
  
Oh wait! I know what I'm thinking of. I wonder if you are using Server GC versus Workstation GC if the behavior would be different. On workstation GC, the thread that does the allocation that triggers the GC does the GC, so if it dies, it takes the app down. 
  
  
I have a dual proc here, so I'll have to try that out in a bit.
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment7</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment7</guid><pubDate>Mon, 28 Jul 2008 17:55:49 GMT</pubDate></item><item><title>Ayende Rahien commented on Some finalizer pitfalls</title><description>Cory,
  
You didn't start the thread :-)
  
You need to call GC.WaitForPendingFinalizers() as well. The finalizer will not run unless it has reason to.
  
Unhandled thread exception will kill the app
  
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment6</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment6</guid><pubDate>Mon, 28 Jul 2008 17:22:15 GMT</pubDate></item><item><title>Cory Foy commented on Some finalizer pitfalls</title><description>But I still agree with Phil. In your example, you were making an assumption that the object would still be valid. 
  
  
However, I think you are wrong in saying it will kill the app. It should only kill the thread. Of course, if your app is just on that one thread...
  
  
Here's an example. Here's my Class1:
  
  
public class Class1 : IDisposable
  
{
  
    public System.IO.FileStream fs;
  
  
    public Class1()
  
    {
  
  
    }
  
  
    ~Class1()
  
    {
  
        fs.Dispose();
  
    }
  
  
    #region IDisposable Members
  
  
    public void Dispose()
  
    {
  
        fs.Dispose();
  
        GC.SuppressFinalize(this);
  
    }
  
  
    #endregion
  
}
  
  
And my Main:
  
  
class Program
  
{
  
    static void Main(string[] args)
  
    {
  
        Console.WriteLine("Hello, Class1!");
  
        System.Threading.Thread t= new System.Threading.Thread(
  
            new System.Threading.ThreadStart(DoIt));
  
        Console.WriteLine("Goodbye, World!");
  
        Console.ReadLine();
  
    }
  
  
    public static void DoIt()
  
    {
  
  
        Class1 c1 = new Class1();
  
        Console.WriteLine("Goodbye, Class1");
  
        Console.ReadLine();
  
    }
  
}
  
  
If you run this, you'll still see Goodbye, World, even though we are throwing an unhandled exception in the finalizer.
  
  
A better practice would be to call Dispose from your finalizer, and then put your checks in there to make sure that any object you are cleaning up is still around to be cleaned up. But you still make a good point to be aware of it.
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment5</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment5</guid><pubDate>Mon, 28 Jul 2008 16:31:57 GMT</pubDate></item><item><title>Ayende Rahien commented on Some finalizer pitfalls</title><description>Haacked,
  
The finalizer must run _once_, so it will still hold true
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment4</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment4</guid><pubDate>Mon, 28 Jul 2008 16:22:23 GMT</pubDate></item><item><title>Haacked commented on Some finalizer pitfalls</title><description>True for now. But I wouldn't rely on that in the future and I tend to be paranoid and defensive when I code. 
  
  
For example, the CLR team has mentioned they may add multiple finalizer threads in the future. See this comment from Brian Grunkemeyer.
  
  
http://blogs.msdn.com/brada/archive/2004/04/28/122423.aspx#123544
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment3</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment3</guid><pubDate>Mon, 28 Jul 2008 16:17:30 GMT</pubDate></item><item><title>Ayende Rahien commented on Some finalizer pitfalls</title><description>Haacked,
  
When the finalizer run, no other code can touch the class
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment2</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment2</guid><pubDate>Mon, 28 Jul 2008 15:56:54 GMT</pubDate></item><item><title>Haacked commented on Some finalizer pitfalls</title><description>Good tip! I generally avoid making any assumptions about my data in the finalizer. I'd probably change that code to something like this:
  
  
~BadClass()
  
{
  
    if(fs != null) {
  
      fs.Dispose();
  
    }
  
}
  
  
Or if there's any place where fs gets set to null, I'd do it this way to avoid potential threading issues:
  
  
~BadClass()
  
{
  
    var thefs = fs;
  
    if(thefs != null) {
  
      thefs.Dispose();
  
    }
  
}
</description><link>http://ayende.com/3458/some-finalizer-pitfalls#comment1</link><guid>http://ayende.com/3458/some-finalizer-pitfalls#comment1</guid><pubDate>Mon, 28 Jul 2008 15:11:43 GMT</pubDate></item></channel></rss>