Поделиться через


Время существования: создание и уничтожение объектов

Обновлен: Ноябрь 2007

Объект как экземпляр класса создается с помощью ключевого слова New. Задачи инициализации перед использованием обычно должны выполняться для новых объектов. При инициализации выполняются следующие действия: открытие файлов, подключение к базам данных, чтение разделов реестра. Visual Basic контролирует инициализацию новых объектов с помощью процедур, называемых конструкторами (специальные методы, позволяющие контролировать инициализацию).

После того, как объект покидает область действия, он освобождается средой CLR. Visual Basic контролирует освобождение системных ресурсов при помощи процедур, называемых деструкторами. Вместе конструкторы и деструкторы обеспечивают создание надежных и прогнозируемых библиотек классов.

Процедуры Sub New и Sub Finalize

В Visual Basic процедуры Sub New и Sub Finalize инициализируют и уничтожают объекты. Эти процедуры заменяют методы Class_Initialize и Class_Terminate, использовавшиеся в Visual Basic 6.0 и более ранних версий. В отличие от Class_Initialize конструктор Sub New может выполняться только один раз — при создании класса. Он может быть вызван явным образом только в первой строке кода другого конструктора того же или производного класса. Следовательно, код метода Sub New всегда выполняется раньше остальных частей кода в классе. Visual Basic 2005 и более поздние версии неявно создают конструктор Sub New во время выполнения, если явно не определена процедура Sub New для создания класса.

Перед освобождением объектов CLR автоматически вызывает метод Finalize для объектов, определяющих процедуру Sub Finalize. Метод Finalize может содержать код, который необходимо выполнить непосредственно перед удалением объекта, например закрытие файлов и сохранение сведений о состоянии. Выполнение Sub Finalize приводит к небольшой потере производительности, поэтому следует использовать метод Sub Finalize только при необходимости явного освобождения объектов.

hks5e2k6.alert_note(ru-ru,VS.90).gifПримечание.

Сборщик мусора в CLR не уничтожает (и не может уничтожить) неуправляемые объекты — объекты, которые выполняются операционными системами напрямую, вне среды CLR. Это вызвано тем, что различные неуправляемые объекты должны быть уничтожены различными способами. Эти сведения непосредственно не связаны с неуправляемыми объектами; они содержатся в документации по объекту. Класс, который использует неуправляемые объекты, должен уничтожать их в своем методе Finalize.

Деструктор Finalize является защищенным методом и может быть вызван только из производного класса или из того класса, к которому он принадлежит. Не следует явным образом вызывать Finalize вне реализации Finalize производного класса, поскольку система автоматически вызывает Finalize при удалении объекта.

В отличие от Class_Terminate, который выполняется сразу же после присвоения объекту значения Nothing, между выходом объекта из области действия и вызовом деструктора Finalize обычно имеется некоторая задержка. Visual Basic 2005 и более поздние версии позволяют использовать второй вид деструктора, Dispose, который может быть явно вызван в любое время для немедленного освобождения ресурсов.

hks5e2k6.alert_note(ru-ru,VS.90).gifПримечание.

Деструктор Finalize не должен создавать исключения, поскольку они не могут обрабатываться приложением и могут привести к его завершению.

Интерфейс IDisposable

Экземпляры класса часто контролируют ресурсы, не управляемые CLR, например дескрипторы Windows и подключения баз данных. Эти ресурсы должны быть уничтожены в методе Finalize класса, чтобы они были освобождены при уничтожении объекта сборщиком мусора. В то же время, сборщик мусора уничтожает объекты только в том случае, если среде требуется дополнительная свободная память. Это может привести к тому, что ресурсы не будут освобождены в течение некоторого времени после выхода объекта из области действия.

Чтобы дополнить сборку мусора, классы могут предоставить механизм активного управления ресурсами системы, если они реализуют интерфейс IDisposable. IDisposable имеет один метод, Dispose, который клиенты должны вызывать при завершении использования объекта. Можно использовать метод Dispose для немедленного освобождения ресурсов и выполнения задач, например для закрытия файлов и подключений к базе данных. В отличие от деструктора Finalize метод Dispose не вызывается автоматически. Для немедленного освобождения ресурсов клиенты класса должны вызывать Dispose явным образом.

Реализация IDisposable

Класс, реализующий интерфейс IDisposable, должен включать эти фрагменты кода:

  • Поле для отслеживания уничтожения объекта:

    Protected disposed As Boolean = False
    
  • Перегрузка Dispose, которая освобождает ресурсы класса. Этот метод должен вызываться методами базового класса Dispose и Finalize:

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                ' Insert code to free managed resources.
            End If
            ' Insert code to free unmanaged resources.
        End If
        Me.disposed = True
    End Sub
    
  • Реализация Dispose, содержащая только следующий код:

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    
  • Переопределенный метод Finalize, содержащий только следующий код:

    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub
    

Наследование от класса, реализующего интерфейс IDisposable

Класс, производный от базового класса, реализующего интерфейс IDisposable, не должен переопределять какой-либо из базовых методов, если только он не использует дополнительные ресурсы, которые необходимо освободить. В этой ситуации производный класс должен переопределять метод Dispose(disposing) базового класса для освобождения своих ресурсов. Это переопределение должно вызывать метод Dispose(disposing) базового класса.

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposed Then
        If disposing Then
            ' Insert code to free managed resources.
        End If
        ' Insert code to free unmanaged resources.
    End If
    MyBase.Dispose(disposing)
End Sub

Не следует переопределять методы базового класса Dispose и Finalize в производном классе. При вызове этих методов из экземпляра производного класса реализация этих методов базового класса вызовет переопределенный метод Dispose(disposing) производного класса.

Иллюстрация

На следующей схеме показано, какие методы наследуются и переопределяются в производном классе.

Удаленный наследуемый график

При использовании этой схемы DisposeFinalize ресурсы производного и базового класса освобождаются правильно. Следующая схема показывает, какие методы вызываются при уничтожении и завершении класса.

Удаленный граф вызовов

Сборка мусора и деструктор Finalize

.NET Framework использует систему сборки мусора с трассировкой ссылок для периодического освобождения неиспользуемых ресурсов. В Visual Basic 6.0 и более ранних версиях для управления ресурсами используется другая система под названием подсчет ссылок. Несмотря на то, что обе системы выполняют одинаковые функции автоматически, существует несколько важных различий.

CLR периодически удаляет объекты, если система определяет, что эти объекты больше не нужны. Если ресурсов системы не хватает, объекты освобождаются быстрее. Существующая задержка между выходом объекта из области действия и его освобождением CLR означает, что, в отличие от Visual Basic 6.0 и боллее ранних версий, невозможно точно определить момент удаления объекта. В таком случае считается, что объекты имеют неопределенное время существования. Если учитывать тот факт, что деструктор Finalize может выполняться не сразу после удаления объекта из контекста, в большинстве случаев неопределенное время существования никак не влияет на способ написания приложений.

Другое различие между системами сборки мусора состоит в использовании ключевого слова Nothing. Чтобы воспользоваться преимуществами подсчета ссылок в Visual Basic 6.0 и более ранних версиях, программисты иногда назначали Nothing переменным объекта для освобождения ссылок этих переменных. Ресурсы объекта освобождались немедленно, если переменная содержала последнюю ссылку на объект. В последних версиях Visual Basic данная процедура также может использоваться: при ее выполнении объект, на который существует ссылка, никогда не освобождает ресурсы мгновенно. Чтобы немедленно освободить ресурсы, используйте метод Dispose объекта, если он доступен. Ключевое слово Nothing следует задавать переменной только в том случае, если ее время жизни велико по сравнению с временем, за которое сборщик мусора обнаруживает объекты без родителя.

См. также

Задачи

Практическое руководство. Реализация схемы Dispose Finalize (Visual Basic)

Основные понятия

Инициализация и прекращение работы компонентов

Методы "Finalize" и деструкторы

Ссылки

Использование конструкторов и деструкторов

New (Visual Basic)

Dispose

Nothing (Visual Basic)

Другие ресурсы

Сведения об изменениях в языке (для пользователей Visual Basic 6.0)