Re[8]: Порядок закрытия FileStream в Dispose
От: Fortnum  
Дата: 16.09.14 03:41
Оценка: -1 :)
Здравствуйте, Fortnum, Вы писали:

F>>Здравствуйте, TK, Вы писали:


F>>>>Я в замешательстве. Как до него может дойти, если он статический, а домен приложения один, выгрузки не предполагается?

TK>>>Приложение рано или поздно завершится. А перед этим придут и финализаторы.

F>>А вот не выгружается что-то Берут сомнения, а приходят ли финализаторы?

F>Да, все-таки они существуют!

А вот так уже нет А почему AppDomain.CurrentDomain.DomainUnload не вызывается? Вроде написано "is about to be unloaded", то есть уже вот-вот, но еще нет.

class AreThereFinalizersForStatic
{
    ~AreThereFinalizersForStatic()
    {
        Console.WriteLine("YES!");
        Console.ReadKey();
    }
}

class Program
{
    static AreThereFinalizersForStatic _areThereFinalizersForStatic = new AreThereFinalizersForStatic();

    static void Main()
    {
        Console.WriteLine("Press ANY key to unload current application domain and exit the application.");

        AppDomain.CurrentDomain.DomainUnload += (obj, e) =>
        {
            Console.WriteLine("Press ANY key to really unload the application domain.");
            Console.ReadKey();
        };

        Console.ReadKey();

        System.Diagnostics.Process.GetCurrentProcess().Kill(); // Kick the static finalizers away
    }
}
Re[8]: Порядок закрытия FileStream в Dispose
От: Fortnum  
Дата: 16.09.14 04:36
Оценка:
Здравствуйте, AndrewVK, Вы писали:

F>>А вот не выгружается что-то Берут сомнения, а приходят ли финализаторы?

AVK>http://msdn.microsoft.com/EN-US/library/9tcc8a46(v=VS.110,d=hv.2).aspx

Нашел интересную статью в тему. Наконец-то понял, почему DanegrousGetHandle такой dangerous

Keep Your Code Running with the Reliability Features of the .NET Framework

A graceful application domain unload uses graceful thread aborts and will allow any relevant finally blocks and any finalizers for objects in that domain to run, but that guarantee is not made for rude application domain unloads (unless in a CER). With rude application domain unloads, the runtime makes no guarantees about back-out code or normal finalizers running. How can a system be reliable under these conditions?

The .NET Framework 2.0 introduces a new kind of finalizer, referred to as a critical finalizer. A critical finalizer is a special kind of finalizer in that it runs even during a rude application domain unload, and it runs within a CER. To implement a critical finalizer, simply derive the class in question from the CriticalFinalizerObject class.

Any finalizer you implement in your derived class will be called as part of a CER and must have reliability guarantees that match those of the reliability contract on CriticalFinalizerObject.Finalize. In other words, you should only derive from CriticalFinalizerObject if your finalizer is guaranteed to succeed and is guaranteed not to corrupt any state when invoked under a CER. When an object that derives from CriticalFinalizerObject is instantiated, the runtime prepares the Finalize method then and there, so it won't have to JIT any code (or do other preparation) when it comes time to actually run the method for the first time.

One of the classes in the .NET Framework that derives from CriticalFinalizerObject is SafeHandle, which lives in the System.Runtime.InteropServices namespace. SafeHandle is a very welcome addition to the .NET Framework and goes a long way towards solving many of the reliability-related problems present in previous versions. At its core, SafeHandle is simply a managed wrapper around an IntPtr with a finalizer that knows how to release the underlying resource referenced by that IntPtr. Since SafeHandle derives from CriticalFinalizerObject, this finalizer is prepared when SafeHandle is instantiated, and will be called from within a CER to ensure that asynchronous thread aborts do not interrupt the finalizer.

Consider the Win32 FindFirstFile function, which is used to enumerate files in a directory. Unfortunately, if an asynchronous exception is thrown after FindFirstFile returns but before the resulting IntPtr handle is stored, that operating system resource is now leaked without any decent hopes for freeing it. SafeHandle comes to the rescue.

The only difference here is that I've replaced the IntPtr return type with SafeFindHandle, where SafeFindHandle is a custom type that derives from SafeHandle. When the runtime invokes a call to FindFirstFile, it first creates an instance of SafeFindHandle. When FindFirstFile returns, the runtime stores the resulting IntPtr into the already created SafeFindHandle. The runtime guarantees that this operation is atomic, meaning that if the P/Invoke method successfully returns, the IntPtr will be stored safely inside the SafeHandle. Once inside the SafeHandle, even if an asynchronous exception occurs and prevents FindFirstFile's SafeFindHandle return value from being stored, the relevant IntPtr is already stored within a managed object whose finalizer will ensure its proper release.

In addition to resource lifetime management, safe handles provide other benefits. First, they aid in memory management by reducing graph promotions for finalization. In the .NET Framework 1.x, a class that requires unmanaged resources typically stores the relevant IntPtr in the class, along with any other managed objects the class relies on. This class almost certainly implements a finalizer to ensure that the IntPtr is properly released. Since finalizable objects always survive at least one garbage collection, the net result is that the entire object graph starting from the class in question survives a collection, all because of that one IntPtr. Since SafeHandle now replaces that IntPtr, and since SafeHandle has its own finalizer, in most scenarios the class that stores the SafeHandle no longer needs its own finalizer. This eliminates those GC graph promotion, thus reducing the stress on the GC. Additionally, removing the finalizer typically means you can get rid of calls to GC.KeepAlive(this) in those objects.

Re[9]: Порядок закрытия FileStream в Dispose
От: Fortnum  
Дата: 16.09.14 05:10
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>А почему AppDomain.CurrentDomain.DomainUnload не вызывается? Вроде написано "is about to be unloaded", то есть уже вот-вот, но еще нет.


Прочитал еще раз. Увидел: "This event is never raised in the default application domain".
Re[8]: Порядок закрытия FileStream в Dispose
От: Fortnum  
Дата: 16.09.14 05:25
Оценка: -1 :)
Здравствуйте, Fortnum, Вы писали:

F>>Здравствуйте, TK, Вы писали:

F>>>>Я в замешательстве. Как до него может дойти, если он статический, а домен приложения один, выгрузки не предполагается?
TK>>>Приложение рано или поздно завершится. А перед этим придут и финализаторы.
F>>А вот не выгружается что-то Берут сомнения, а приходят ли финализаторы?
F>Да, все-таки они существуют!

А вот так еще можно от всех файналайзеров избавиться

The total execution time of all ProcessExit event handlers is limited, just as the total execution time of all finalizers is limited at process shutdown. The default is two seconds.


class AreThereFinalizersForStatic
{
    ~AreThereFinalizersForStatic()
    {
        Console.WriteLine("YES!");
    }
}

class Program
{
    static AreThereFinalizersForStatic _areThereFinalizersForStatic = new AreThereFinalizersForStatic();

    static void Main()
    {
        Console.WriteLine("Press ANY key to unload current application domain and exit the application.");

        AppDomain.CurrentDomain.ProcessExit += (obj, e) =>
        {
            Console.WriteLine("Just wait 2 sec.");
                
            Thread.Sleep(Timeout.Infinite);
        };
            
        Console.ReadKey();
    }
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.