Skip to content

Instantly share code, notes, and snippets.

@dagrigorev
Created September 27, 2020 19:15
Show Gist options
  • Save dagrigorev/3fbd975f9f0de8ce91edff8c330b8185 to your computer and use it in GitHub Desktop.
Save dagrigorev/3fbd975f9f0de8ce91edff8c330b8185 to your computer and use it in GitHub Desktop.
Познание C#. Запись №1.
Это первая заметка из серии "Познание шарпа". Сюда записываю свои заметки по работе на платформе .NET C#.
На эту мысль меня натолкнули кучи пройденных собеседований на различные вакансии шарп разработчика.
Хочу оставить здесь свою заметку по поводу сборщика мусора в шарпе (GC или GarbageCollector).
В одном собесе был задан вопрос, а что будет, если на финализаторе класса возникнет исключение?
(кстати, а что вы думаете на этот счет?)
Тут стоит вспомнить немного теории. При создании объекта с финализатором, "ссылка на него добавляется в специальную очередь,
называемую очередью финализации (finalization queue). Эта очередь воспринимается сборщиком мусора как корень,
в том смысле, что даже если в приложении не останется ни одной ссылки на объект, он все равно будет удерживаться
в памяти очередью финализации.
Когда объект становится ненужным в приложении, сборщик мусора обнаружит, что на объект указывает только одна ссылка
- из очереди финализации - и переместит ссылку на объект в другую очередь, называемую очередью объектов, готовых к завершению
(freachable queue). Эта очередь также воспринимается как корень, поэтому объект по-прежнему будет удерживаться в памяти.
Управляет очередью финализации - поток финализации (запускается всегда как thread_priority_highest). Этот поток постоянно
находится в ожидании появления события финализации (finalization event). Это событие посылается сборщиком мусора, если хотя
бы один объект был перемещен им в очередь объектов, готовых к завершению. Поток финализации удаляет ссылку из очереди и одновременно
выполняет метод-финализатор объекта. В следующем цикле сборки мусора сборщик обнаружит отсутствие ссылок на объект и освободит
занимаемую им память." (https://professorweb.ru/my/csharp/optimization/level3/3_6.php)
Однако, при возникновения исключения в методе финализации приложение может войти в режим аварийного завершения (critical shutdown).
В результате приложение закроется с ошибкой необработанного исключение (UnhandledException).
Пример лога с событием об ошибке:
"Application: Experimental.exe
CoreCLR Version: 4.700.20.41105
.NET Core Version: 3.1.8
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException: finalizer exception."
Причем, интересный факт, сначала возникает ошибка Runtime машины, а затем - ошибка самого приложения.
@dagrigorev
Copy link
Author

dagrigorev commented Sep 27, 2020

Вариант решения этой проблемы. Попытка обработать событие возникновения UnhandledException у домена приложения.
См. https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.unhandledexception?redirectedfrom=MSDN&view=netcore-3.1

Пример:

using System;
using System.Security.Permissions;
public class Example
{
   [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlAppDomain)]
   public static void Main()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
     currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

     try {
         throw new Exception("1");
     } catch (Exception e) {
         Console.WriteLine("Catch clause caught : {0} \n", e.Message);
     }
     throw new Exception("2");
  }

   static void MyHandler(object sender, UnhandledExceptionEventArgs args)
   {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);
      Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
   }
}

@dagrigorev
Copy link
Author

Или самому обработать исключение непосредственно в финализаторе.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment