Неуправляемые ресурсы и освобождение ранее выделенной области памяти
После первой паузы файл log1.txt уже создан, и мы можем просмотреть его содержимое с помощью стандартной системной программы Блокнот (Notepad). Если попробовать удалить файл, получим нарушение процедуры совместного использования (общих ресурсов), т.е. нарушение условий коллективного доступа (ошибка совместного доступа, т.к. файл уже открыт другим приложением), как показано на рис. 8.2.
После второй паузы ранее выделенная для log1.txt область памяти будет освобождена и его можно будет удалить. Файл Iog2.txt к этому моменту уже был создан и открыт. А до третьей паузы будет создан Iog3.txt. Но объектной ссылке на Iog2.txt было присвоено новое значение, поэтому теперь клиентская программа не может освободить область памяти, ранее выделенную для второго объекта.
Если бы Dispose (Освободить ранее выделенную область памяти) был единственным механизмом для удаления второго объекта, нам бы не повезло. К счастью, в классе SimpleObject реализован деструктор, так что при следующей сборке мусора удастся избавиться от второго объекта должным образом. Можно увидеть результат завершения, выполнив программу до конца. Второй объект действительно завершается и ранее выделенная для него область памяти освобождается. Фактически при завершении работы прикладной области деструкторы вызываются для всех не уничтоженных объектов, даже для объектов, которые все еще являются доступными.
Рис. 8.2. Попытка удалить открытый файл приводит к нарушению процедуры совместного использования, т.е. к нарушению условий коллективного доступа. В результате появляется сообщение об ошибке совместного доступа, т.к. файл уже открыт другим приложением
В нашем коде мы явно делаем третий объект недоступным, присваивая указателю пустой указатель (log = null), и принудительно устраиваем сборку мусора, вызывая GC::Collect (Сборщик мусора::Собрать). Потом приложение на некоторое время переходит в режим. ожидания, чтобы сборщик мусора выполнил свою работу до конца перед завершением прикладной области. Наша тестовая программа несколько искусственна, так как сборка мусора недетерминирована.
Сборщик мусора вызывается автоматически при выходе из программы и завершении работы прикладной области. Однако при этом системные объекты, такие как Console (Консоль), также закрываются. Так как нельзя полагаться на порядок завершения, можно получить исключение при вызове WriteLine внутри деструктора. Явный вызов GC::Collect (СБОРЩИК МУСОРА::Собрать) вызывает принудительную сборку мусора в то время, когда системные объекты все еще открыты. Если мы опустим последние три строки из метода Мат (Главный), то можем получить идентичный вывод, но можем также получить и исключение.
Дополнительное имя для Dispose (Освободить ранее выделенную область памяти)
Стандартное имя метода, производящего очистку – Dispose (Освободить ранее выделенную область памяти). Соглашение состоит в том, что, как только ранее выделенная для объекта область памяти освобождается, такой объект завершает свою работу. Однако в некоторых случаях, например для файла, тот же самый экземпляр объекта мог бы использоваться повторно. Файл может быть открыт, закрыт, а затем снова открыт. При этом стандартное соглашение об именовании гласит, что метод для очистки должен называться Close (Закрыть). В других случаях может использоваться другое подходящее имя.
Чтобы вполне естественно, если бы в нашем классе SimpleLog имелся метод Open (Открыть). В этом случае метод для очистки логично было бы назвать Close (Закрыть). Простоты ради, мы не реализовали метод Open (Открыть), и поэтому придерживались имени Dispose (Освободить ранее выделенную область памяти).