Глава.21 .Автоматическое.управление.памятью.(уборка.мусора)
можные в обычных условиях
1
. Если метод
Finalize
блокируется (например, входит
в бесконечный цикл или ожидает объекта, который никогда не будет освобожден),
специальный поток не сможет вызывать методы
Finalize
. Данная ситуация крайне
нежелательна, потому что приложение не сможет освободить память, занимаемую
финализируемыми объектами. Если метод
Finalize
выдает необработанное ис-
ключение, процесс завершается; перехватить такое исключение невозможно.
Как видите, использование методов
Finalize
связано с многочисленными
оговорками и требует значительной осторожности от разработчика. Эти методы
предназначены исключительно для освобождения системных ресурсов. Чтобы
упростить их использование, я рекомендую по возможности обойтись без пере-
определения метода
Finalize
класса
Object
; вместо этого лучше использовать
вспомогательный класс из библиотеки FCL. Этот класс переопределяет
Object
и выполняет ряд дополнительных операций, о которых будет рассказано позже.
Вы можете создать собственные классы, производные от него и наследующие все
вспомогательные операции.
Если вы создаете управляемый тип, использующий системный ресурс, соз-
дайте класс, производный от специального базового класса
System.Runtime.
InteropServices.SafeHandle
, который выглядит примерно так (комментарии
в коде метода мои):
public abstract class SafeHandle : CriticalFinalizerObject, IDisposable {
// Это дескриптор системного ресурса
protected IntPtr handle;
protected SafeHandle(IntPtr invalidHandleValue, Boolean ownsHandle) {
this.handle = invalidHandleValue;
// Если значение ownsHandle равно true, то системный ресурс закрывается
// при уничтожении объекта, производного от SafeHandle,
// уборщиком мусора
}
protected void SetHandle(IntPtr handle) {
this.handle = handle;
}
// Явное освобождение ресурса выполняется вызовом метода Dispose
public void Dispose() { Dispose(true); }
// Здесь подойдет стандартная реализация метода Dispose
// Настоятельно не рекомендуется переопределять этот метод!
protected virtual void Dispose(Boolean disposing) {
// В стандартной реализации аргумент, вызывающий метод
// Dispose, игнорируется
// Если ресурс уже освобожден, управление возвращается коду
// Если значение ownsHandle равно false, управление возвращается
// Установка флага, означающего, что этот ресурс был освобожден
1
Возможно, в будущих версиях CLR для повышения производительности будут исполь-
зоваться множественные потоки финализации.
579
Освобождение.ресурсов.при.помощи.механизма.финализации
// Вызов виртуального метода ReleaseHandle
// Вызов GC.SuppressFinalize(this), отменяющий вызов метода финализации
// Если значение ReleaseHandle равно true, управление возвращается коду
// Если управление передано в эту точку,
// запускается ReleaseHandleFailed Managed Debugging Assistant (MDA)
}
// Здесь подходит стандартная реализация метода финализации
// Настоятельно не рекомендуется переопределять этот метод!
~SafeHandle() { Dispose(false); }
// Производный класс переопределяет этот метод,
// чтобы реализовать код освобождения ресурса
protected abstract Boolean ReleaseHandle();
public void SetHandleAsInvalid() {
// Установка флага, означающего, что этот ресурс был освобожден
// Вызов GC.SuppressFinalize(this), отменяющий вызов метода финализации
}
public Boolean IsClosed {
get {
// Возвращение флага, показывающего, был ли ресурс освобожден
}
}
public abstract Boolean IsInvalid {
// Производный класс переопределяет это свойство
// Реализация должна вернуть значение true, если значение
// дескриптора не представляет ресурс (обычно это значит,
// что дескриптор равен 0 или @1)
get
}
// Эти три метода имеют отношение к безопасности и подсчету ссылок
// Подробнее о них рассказывается в конце этого раздела
public void DangerousAddRef(ref Boolean success) {...}
public IntPtr DangerousGetHandle() {...}
public void DangerousRelease() {...}
}
Рассматривая класс
SafeHandle
, прежде всего нужно отметить, что он наследует
от класса
CriticalFinalizerObject
, определенного в пространстве имен
System.
Runtime.ConstrainedExecution
. Это гарантирует «особое обращение» со стороны
CLR к этому классу и другим, производным от него классам. В частности, CLR на-
деляет этот класс тремя интересными особенностями:
При первом создании любого объекта, производного от типа
Critical-
FinalizerObject
, CLR автоматически запускает JIT-компилятор, компили-
рующий все методы финализации в иерархии наследования. Компиляция
этих методов после создания объекта гарантирует, что системные ресурсы
580
Do'stlaringiz bilan baham: |