4_C#_сборка_мусора_исключения_Disposable.pptx
- Количество слайдов: 16
Жизненный цикл объекта ü Создание объекта при вызове оператора new • Под объект выделяется область памяти из управляемой кучи. • Область памяти инициализируется при работе конструктора. • Возможно захватывается ресурс, например, открывается файл или устанавливается соединение с базой данных. ü Использование объекта • Вызываются методы объекта, производится доступ к полям данных объекта. ü Уничтожение объекта (точное время не определено) • При помощи деструктора (финализатора) объект превращается в область памяти. • Область памяти возвращается системе. ü Освобождением занятых ресурсов занимается сборщик мусора.
Деструктор ü В классе можно определить деструктор. ü В отличие от C++ порядок вызова деструкторов в C# не определен. Перед освобождением памяти сборщик мусора вызывает деструктор, но возможны ситуации, когда деструктор для объекта не вызывается совсем. ü Определять свои деструкторы нужно только в случае крайней необходимости - они создают значительную нагрузку на систему. ü На самом деле наличие в классе деструктора означает неявное переопределение метода Finalize class T { ~T() { Console. Write. Line(“T destructed”); } } class T { protected override void Finalize(){ try { Console. Write. Line(“T destructed”); } finally { base. Finalize(); } } }
Сборщик мусора ( Garbage Collector) ü CLR использует модель сборки с поколениями 0 – (128 -256 -512 K) – динамически настраивается 1 – (2 Mб) 2 – (10 Mб) ü Сборщик мусора начинает работу, когда заполнено поколение 0, неиспользуемые объекты освобождаются, а все остальные перемещаются в поколение 1. ü Для больших объектов (> 85000 байт) своя куча и свой алгоритм работы GC. Массивные объекты сборщик мусора не перемещает. ü Алгоритмы сборки отличаются в debug и release версиях и в различных версиях OC. Информация: 1. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft. NET Framework 2. 0 на языке C#. - Изд. Microsoft Press. Русская редакция, 2007. 2. Маони Стивенс (Maoni Stephens). Представляем кучу для массивных объектов MSDN MAGAZINE , июнь 2008.
Сборка мусора для объектов с завершением ü Перед вызовом Ctor объекты с завершением (с Dtor) заносятся в специальный список объектов, для которых надо вызвать Dtor перед освобождением памяти. ü При сборке мусора в поколении 0 объекты с завершением не уничтожаются, а заносятся в специальную очередь завершения. Очередь завершения обрабатывает специальный высокоприоритетный поток. В каком случае Dtor может быть не выполнен? ü После завершения работы приложения CLR вызывает Finalize() для каждого объекта с завершением, но если время возврата из него более 2 сек, CLR завершает процесс и остальные методы Finalize() не вызываются.
Исключения ü В коде, использующем библиотеки классов, обработка ошибок во время выполнения программы должна быть разделена на две части : • генерация сообщения об ошибке, которая не может быть обработана локально; • обработка ошибки в том месте, где достаточно информации для анализа нестандартной ситуации и ее обработки. ü Механизм исключений C# дает возможность писать устойчивый и простой в сопровождении код. ü Можно передать произвольный объем информации в точку обработки ошибки.
Исключения в C# и C++ ü Механизм исключений в C# почти полностью совпадает с механизмом исключений в C++. Отличия: • все исключения C# должны быть экземплярами классов, производных от класса System. Exception; • в C# можно использовать блок finally, который выполняется в любом случае, независимо от того, брошено исключение или нет; • в C# для системных исключений (переполнение, деление на нуль или нулевая ссылка) также определены классы, которые обрабатываются наравне с исключениями уровня приложения. ü Исключение явно порождается выражением throw new File. Not. Found. Exception(“test. dat”);
Исключения. Пример class Program { static void Main(string[] args) { double[] arr = { 1. 1, 2. 2 }; ABC abc = new ABC(arr); try { Console. Write. Line("Before 1"); abc[0] = -1; Console. Write. Line("After 1"); } catch (Exception ex) { Console. Write. Line(ex. Message); } finally { Console. Write. Line("finally 1"); } Console. Write. Line("After try 1n"); try { Console. Write. Line("Before 2"); abc[0] = 10; abc[3] = 10; Console. Write. Line("After 2"); } catch (Exception ex) { Console. Write. Line(ex. Message); } finally { Console. Write. Line("finally 2"); } Console. Write. Line("After try 2n“ + abc); } } public class ABC { double [] dt = new double[0]; public ABC( double[] dt) {this. dt = dt; } public double this[int j] { get { return dt[j]; } set { if (value < 0) throw new Exception (“Error: Value < 0"); else dt[j] = value; } } public override string To. String() { string str = ""; foreach (double d in dt) str += d + " "; return str; } } Before 1 Error: Value < 0 finally 1 After try 1 Before 2 Index was outside the bounds of the array. finally 2 After try 2 10 2, 2
Тип System. Exception ü Все исключения должны иметь тип System. Exception или быть его потомками public class Exception : ISerializable { … public Exception(); public Exception( string message, Exception inner. Exception ); public virtual string Message { get; } public Exception Inner. Exception { get; } // предыдущее исключение, // если данное было сгенерировано при // обработке предыдущего. public virtual string Stack. Trace { get; } // строка с именами // и сигнатурами последовательных вызовов, // которые привели к генерации исключения. }
Иерархия классов-исключений ( часть классов) System. Object System. Exception System. Argument. Exception System. Arithmetic. Exception System. Array. Type. Mismatch. Exception System. Bad. Image. Format. Exception System. Index. Out. Of. Range. Exception System. Invalid. Cast. Exception System. Null. Reference. Exception System. Out. Of. Memory. Exception System. Execution. Engine. Exception System. Stack. Overflow. Exception . . . System. Object System. Exception System. IOException System. IO. Directory. Not. Found. Exception System. IO. End. Of. Stream. Exception System. IO. File. Load. Exception System. IO. File. Not. Found. Exception System. IO. Path. Too. Long. Exception
Блок finally ü Выполняется в любом случае, независимо от того, брошено исключение или нет. ü Если нет исключения, выполняются все операторы в блоке try, а затем операторы блока finally. ü Если брошено исключение, CLR просматривает стек вызовов в поиске обработчика с нужным типом фильтра, и выполняет • сначала блок finally в тех методах, где нет обработчика с требуемым фильтром; • затем блок catch; • затем finally из блока try с обработчиком. ü Допустимые конфигурации • try – catch – finally • try – catch • try – finally
Блок finally. Пример File. Stream s. W = null; try { s. W = File. Create(". . \Data. bin"); Binary. Formatter bin. F = new Binary. Formatter(); bin. F. Serialize(s. W, tc 1); bin. F. Serialize(s. W, tc 2); } catch(Exception ex) { Console. Write. Line(ex. Message); } finally { if (s. W != null) s. W. Close(); }
Порядок обработки исключений static void Main ( string[] args) {… код C# … Abc abc = new Abc(); try { abc. Method 1(); … код C# … 1 } сatch (Exception 1 ex) { … 1 обработка исключений класса … Exception 1 и его потомков } catch (Exception 2 ex) { … 2 обработка исключений класса … Exception 2 и его потомков } finally { … 1 … } } partial class Abc { public void Method 1() { … код C# try { … код C# … 2 Method 2(); … код C# … 3 } catch (Exception 3 ex) { … 3 обработка исключений класса … Exception 3 и его потомков } finally { … 2 …} … код C# … 4 } partial class Abc { public void Method 2() { … код C# try { … код C# … 5 if( < условие>) throw new Exception. N(); … код C# … 6 } сatch (Exception 1 ex) { … 4 обработка исключений класса … Exception 1 и его потомков } catch (Exception 4 ex) { … 5 обработка исключений класса … Exception 4 и его потомков } finally { … 3 … } … код C# … 7 } <условие>== false код 2 код 5 код 6 finally 3 код 7 код 3 finally 2 код 4 код 1 finally 1 <условие>== true throw Exception 1 код 2 код 5 catch 4 finally 3 код 7 код 3 finally 2 код 4 код 1 finally 1 <условие>== true throw Exception 3 код 2 код 5 finally 3 catch 3 finally 2 код 4 код 1 finally 1 <условие>== true throw Exception 2 код 5 finally 3 finally 2 catch 2 finally 1
Задача освобождения ресурсов. Решение в C++ void main () { try {. . . код С++ f(); . . . код С++ } catch (exception ex) {. . . код С++ } } void f() { Resource R (); // R. Lock(); Lock_Resource LR(R); f. Inner(R); // R. Unlock(); } void f. Inner (Resource& rc) {. . . код бросает исключение } class Resource { public: void Lock() {. . . захват ресурса } void Unlock() {. . . освобождение ресурса } Resource () {. . . } private: . . . данные }; class Lock_Resource { public: Lock_Resource (Resource &rci) { rc = rci; rc. Lock(); } ~Lock_Resource() { rc. Unlock(); } private: Resource& rc; };
Задача освобождения ресурсов. Решение в C#. public static void Main ( string[] args) { try {. . . код С# f(); . . . код С# } catch (exception ex) {. . . код С# } } public void f() { Resource R (); R. Lock(); try { f. Inner(R); } finally { R. Unlock(); } } void f. Inner (Resource& rc) {. . . код бросает исключение } class Resource { public void Lock() {. . . захват ресурса } public void Unlock() {. . . освобождение ресурса } public Resource () {. . . } private: . . . данные }
Типы с явным освобождением ресурсов ü В типах, которые поддерживают модель детерминированного освобождения ресурсов, следует реализовать метод void Dispose(); в котором размещают код, освобождающий ресурсы. ü Оператор using - краткая форма try-finally class A : IDisposable { } class B : IDisposable { } using(a = new A()) using(b = new B()) { // … } a = new A(); try { b = new B(); try { … } finally { b. Dispose(); } } finally { a. Dispose(); }
Пример реализации метода Dispose() public class My. Resource: IDisposable { private Int. Ptr handle; // unmanaged resource private Component component = new Component(); // managed resource private bool disposed = false; public void Dispose() { Dispose(true); GC. Suppress. Finalize(this); } private void Dispose(bool disposing) { // disposing == true явный вызов из Dispose() // disposing == false вызов из деструктора if ( !this. disposed ) { if ( disposing ) // явный вызов Dispose() { component. Dispose(); // Dispose managed resources. } Close. Handle(handle); // Clean up unmanaged resources } disposed = true; } ~My. Resource() { Dispose(false); } }
4_C#_сборка_мусора_исключения_Disposable.pptx