Глава.21 .Автоматическое.управление.памятью.(уборка.мусора)
освободятся, как только объект станет мусором. Без немедленной компиляции
метода финализации может оказаться, что ресурс будет выделен и использован,
но не освобожден. При недостатке памяти CLR может не хватить памяти для
компиляции метода финализации; в этом случае метод не будет исполнен, что
приведет к утечке системных ресурсов. Также ресурсы не будут освобождены,
если код в методе финализации содержит ссылку на тип в другой сборке, которая
не была обнаружена CLR.
CLR вызывает метод финализации для типов, производных от
CriticalFinalizer-
Object
, после вызова методов финализации для типов, непроизводных от
CriticalFinalizerObject
. Благодаря этому классы управляемых ресурсов,
имеющие метод финализации, могут успешно обращаться к объектам, произ-
водным от
CriticalFinalizerObject
, в их методах финализации. Так, метод
финализации класса
FileStream
может сбросить данные из буфера памяти на
диск в полной уверенности, что дисковый файл еще не был закрыт.
CLR вызывает метод финализации для типов, производных от
CriticalFinalizer-
Object
, если домен приложения был аварийно завершен управляющим прило-
жением (например, Microsoft SQL Server или Microsoft ASP.NET). Это гаранти-
рует освобождение системных ресурсов даже в том случае, когда управляющее
приложение больше не доверяет работающему внутри него управляемому коду.
Также следует отметить, что класс
SafeHandle
является абстрактным: пред-
полагается, что разработчик создаст класс, производный от
SafeHandle
, который
переопределит защищенный конструктор, абстрактный метод
ReleaseHandle
и абстрактное свойство
IsInvalid
метода доступа
get
.
В Windows для операций с системными ресурсами обычно используются де-
скрипторы (32-разрядные в 32-разрядных системах, 64-разрядные в 64-разрядных
системах). В классе
SafeHandle
определяется защищенное поле
IntPtr
с именем
handle
. Большинство дескрипторов считаются недействительными при равенстве
их значения 0 или –1. Пространство имен
Microsoft.Win32.SafeHandles
содержит
еще один вспомогательный класс
SafeHandleZeroOrMinusOneIsInvald
вида:
public abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle {
protected SafeHandleZeroOrMinusOneIsInvalid(Boolean ownsHandle)
: base(IntPtr.Zero, ownsHandle) {
}
public override Boolean IsInvalid {
get {
if (base.handle == IntPtr.Zero) return true;
if (base.handle == (IntPtr) (-1)) return true;
return false;
}
}
}
581
Освобождение.ресурсов.при.помощи.механизма.финализации
Обратите внимание, что класс
SafeHandleZeroOrMinusOneIsInvalid
явля-
ется абстрактным, поэтому надо создать дочерний класс, который переопреде-
лит защищенный конструктор и абстрактный метод
ReleaseHandle
. На плат-
форме Microsoft .NET Framework есть несколько открытых классов, производ-
ных от
SafeHandleZeroOrMunusOneIsInvalid
, в числе которых
SafeFileHandle
,
SafeRegistryHandle
,
SafeWaitHandle
и
SafeMemoryMappedViewHandle
. А так
выглядит класс
SafeFileHandle
:
public sealed class
SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid {
public SafeFileHandle(IntPtr preexistingHandle, Boolean ownsHandle)
: base(ownsHandle) {
base.SetHandle(preexistingHandle);
}
protected override Boolean ReleaseHandle() {
// Сообщить Windows, что системный ресурс нужно закрыть
return Win32Native.CloseHandle(base.handle);
}
}
Класс
SafeWaitHandle
реализован сходным образом. Единственной причиной
для создания разных классов с похожими реализациями является обеспечение
безопасности типов: компилятор не позволит использовать файловый дескриптор
в качестве аргумента метода, принимающего дескриптор блокировки, и наоборот.
Метод
ReleaseHandle
класса
SafeRegistryHandle
вызывает Win32-функцию
RegCloseKey
.
Жаль, что на платформе .NET Framework отсутствуют дополнительные клас-
сы, служащие оболочкой различных системных ресурсов, например таких, как
SafeProcessHandle
,
SafeThreadHandle
,
SafeTokenHandle
,
SafeLibraryHandle
(его
метод
ReleaseHandle
вызывал бы Win32-функцию
FreeLibrary
),
SafeLocalAl-
locHandle
(его метод
ReleaseHandle
вызывал бы Win32-функцию
LocalFree
)
и т. п.
Все эти классы (а также некоторые другие) есть в библиотеке FCL. Однако они
не предоставляются для открытого использования, являясь внутренними классами
сборок, в которых они определяются. Microsoft не афиширует эти классы, чтобы не
выполнять их полное тестирование и не тратить время на их документирование.
Если же вам придется с ними столкнуться, рекомендую воспользоваться утилитой
ILDasm exe
или другим IL-декомпилятором, чтобы извлечь код этих классов и инте-
грировать его в исходный текст программы. Все эти классы тривиально реализуются
и их несложно написать самостоятельно.
Классы, производные от
SafeHandle
, чрезвычайно полезны — ведь они гаран-
тируют освобождение системного ресурса в ходе уборки мусора. Стоит добавить,
что у типа
SafeHandle
есть еще две функциональные особенности. Во-первых,
когда производные от него типы используются в сценариях взаимодействия
582
Do'stlaringiz bilan baham: |