Оператор Dispose

Оператор Dispose в языке Fore предназначен для решения довольно узкого класса проблем, связанных с невозможностью определения момента освобождения неиспользуемых объектов. Уничтожение созданных и уже неиспользующихся объектов (на которые нет ссылок) производится сборщиком мусора (garbage collector). Запуск сборщика мусора в основном производится в моменты простоя системы. Как следствие между обнулением ссылок на объект и его фактическим уничтожением может пройти довольно большой период времени. Наличие этого периода, а также неопределенность момента его наступления, могут вызывать проблемы при разработке. Рассмотрим это на следующем классическом примере:

Sub Main;

Var

FileName: String;

Fs: FileStream;

Begin

FileName := Path.GetTempFileName;

Fs := New FileStream.Create(FileName, FileOpenMode.Create, FileShare.Exclusive);

Try

// Do something

Finally

Fs := Null;

File.Delete(FileName);

End Try;

End Sub Main;

В данном примере создается временный файл, затем с ним производятся какие-либо действия, после чего файл удаляется. При запуске примера на строке File.Delete возникнет стандартная исключительная ситуация "Процесс не может получить доступ к файлу, т.к. файл занят другим процессом". Казалось бы, что после присваивания переменной Fs значения Null единственная ссылка на объект "файловый поток" прекратит существование и файл будет закрыт. Фактически этого не происходит, так как объект "файловый поток" остается в памяти, несмотря на отсутствие ссылок, до следующей сборки мусора. Как следствие, файл не освобождается и не может быть удален.

Таким образом, мы приходим к тому, что требуется механизм своевременного освобождения ссылок на ресурсы. Для этого и предназначен оператор Dispose. Если по каким-либо причинам необходимо освободить ссылку на объект и уничтожить его, то необходимо использовать оператор Dispose с указанием переменной.

При использовании оператора есть несколько ограничений:

  1. Данный оператор эффективно применять только к объектам системных классов, которые являются обертками над COM-объектами. Для объектов пользовательских классов, описанных прикладными разработчиками, применять его бессмысленно.

  2. После выполнения оператора Dispose не происходит очистка ссылки на объект-обертку, переменной содержащей ссылку Null не присваивается. Производится освобождение ссылки на системный COM-объект, что позволяет ему уничтожиться и освободить занятые ресурсы. После вызова оператора Dispose любые обращения к объекту будут вызывать исключительную ситуацию.

  3. Если на данный объект есть другие ссылки, то вызов оператора Dispose ожидаемого эффекта не даст. Для освобождения внутреннего COM-объекта необходимо разорвать все ссылки на него.

В итоге корректно работающий пример будет выглядеть таким образом:

Sub Main;

Var

FileName: String;

Fs: FileStream;

Begin

FileName := Path.GetTempFileName;

Fs := New FileStream.Create(FileName, FileOpenMode.Create, FileShare.Exclusive);

Try

// Do something

Finally

Dispose Fs;

File.Delete(FileName);

End Try;

End Sub Main;

См. также:

Операторы