Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finalizer not called after unhandled exception even with CriticalFinalizerObject

Tags:

c#

.net

finalizer

I have test code like this:

public class A : CriticalFinalizerObject 
{
    ~A()
    {
        File.WriteAllText("c:\\1.txt", "1z1z1");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        throw new Exception();
    }
}

First I tried running it without deriving A from CriticalFinalizerObject. Finalizer wasn't called after end of this program. That surprised me as I thought it was more deterministic but okay. Then I've read about CriticalFinalizerObject's that ensure their finalizers will be called. I derived A from it. Guess what. It still doesn't get executed. What am I doing/understanding wrong?

(Please don't write obvious stuff about garbage collector being non-deterministic, I know that. It is not the case as the program is over and I imagined I could safely clean up after a nice unhandled managed exception.)

like image 931
IlyaP Avatar asked May 18 '12 16:05

IlyaP


1 Answers

Firstly, let's read about CriticalFinalizerObject in MSDN, we can read, that:

In classes derived from the CriticalFinalizerObject class, the common language runtime (CLR) guarantees that all critical finalization code will be given the opportunity to execute, provided the finalizer follows the rules for a CER, even in situations where the CLR forcibly unloads an application domain or aborts a thread.

The main word here is UNLOAD.

Secondly, let's read MSDN again, this time about Exceptions in managed threads:

If these exceptions are unhandled in the main thread, or in threads that entered the runtime from unmanaged code, they proceed normally, resulting in termination of the application.

The main word is TERMINATION.

So, when there is an unhandled exception in main thread - app terminates, but CriticalFinalizerObject helps only on unloading of Domain.

For example, CriticalFinalizerObject can helps in such situation:

// Create an Application Domain:
AppDomain newDomain = AppDomain.CreateDomain("NewApplicationDomain");

// Load and execute an assembly:
newDomain.ExecuteAssembly(@"YouNetApp.exe");

//Unload of loaded domain
AppDomain.Unload(newDomain);

This is a situation, where domain was unloaded, and CriticalFinalizerObject guarantee you, that your finalizer will be called.

In your situation with terminating of app you can try to subscribe to

AppDomain.CurrentDomain.UnhandledException

and manually finalize your objects.

UPD: Jeffrey Richter in his book "CLR via C#" wrote about CriticalFinalizerObject, that it's for situations where you send your code for example to SQLServer, which can run C# as a procedures. In such case CriticalFinalizerObject helps you to clean your object, if SQLServer will unload your library's Domain. Also CriticalFinalizerObject is for situations where you need in finalizer of object to call method of another object, because of CriticalFinalizerObject guarantee you, that it's finalizer will be called after finalizers of all non CriticalFinalizerObject objects.

like image 113
igofed Avatar answered Oct 20 '22 20:10

igofed