C# одноразовый вопрос

Будет ли сборщик мусора автоматически освобождать неуправляемые ресурсы (независимо от того, что на самом деле), связанные с некоторыми IDisposable Например, если я забыл написать using заявление?

Очевидно, я не знаю, когда это произойдет, но можно ли оставить IDisposable к GC когда я не забочусь об этих ресурсах, и я в порядке с тем, что они будут в конечном итоге уничтожены?

6 ответов

Решение

Будет ли сборщик мусора автоматически освобождать неуправляемые ресурсы (независимо от того, что на самом деле) связано с каким-либо IDisposable экземпляром, если, например, я забыл написать с помощью оператора?

Обычно, но не обязательно. Автору одноразового ресурса нужно поступать правильно.

Очевидно, я не знаю, когда это произойдет, но нормально ли оставлять ID доступным для GC, когда мне нет дела до этих ресурсов, и я в порядке с тем, что они будут в конечном итоге уничтожены?

Ваш вопрос предполагает ложь. Сборщик мусора никогда не вызывает Dispose, никогда. Скорее сборщик мусора вызывает деструктор (или "финализатор", если хотите). Это деструктор, который может вызвать или не вызвать Dispose для забывчивого пользователя.

Ваш вопрос также указывает на плохое отношение. Вам может быть все равно, если ресурсы освобождаются поздно, но другая программа, безусловно, может заботиться! Что если ваш клиент запускает две программы, которые обе пытаются получить доступ к одному и тому же неуправляемому ресурсу, одна написана вами, а другая - кем-то другим? Быть хорошим гражданином; освободите свои дефицитные ресурсы, как только вы закончите с ними, чтобы другие программы могли их использовать. Это реальная цель "использования" - быть вежливым, обеспечивая быстрое восстановление ограниченных ресурсов.

Правильная реализация шаблона Dispose гарантирует, что деструктор очищает неуправляемые ресурсы, если пользователь забывает вызывать Dispose, и гарантирует, что деструктор НЕ очищает ресурсы, если они помнят.

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

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

Да, они будут очищены в конце концов. Вам нужно только использовать using (хех..) когда вам нужна детерминированная очистка ресурсов, например, для GDI, Sql и другого кода, основанного на дескрипторе системы, или для потенциально загружаемых объектов, таких как DataTable,

Изменить: предполагается, что вы реализовали Dispose шаблон правильно и ваш вызов деструктора Dispose,

Если объект правильно реализует интерфейс IDisposable, включив условный вызов метода Dispose в финализаторе, GC будет запускать удаление объекта во время сбора (через финализатор).

Есть вещи, которые делают это невозможным, но если следовать стандартному шаблону, то он должен работать в большинстве случаев.

Если объект не включает код выбытия в финализаторе, все ставки отключены. Неуправляемые ресурсы могут оставаться нераспределенными до появления солнечных сверхновых.

Нет, не обязательно Это зависит от того, как вы получили неуправляемые ресурсы.

Если у вас есть прямой доступ к неуправляемым ресурсам (возможно, IntPtr) тогда вы должны либо иметь финализатор или использовать SafeHandle... в противном случае вы определенно можете утечь неуправляемые ресурсы

Если ваш тип просто имеет ссылку на что-то вроде FileStream, тогда вы должны ожидать, что этот тип будет иметь финализатор.

Теперь довольно редко требуется прямой доступ к неуправляемым ресурсам из вашего типа, и если вы используете типы инфраструктуры, они действительно должны очищаться соответствующим образом (но недетерминированно). Тем не менее, это возможно.

Любой IDisposable в системных библиотеках будет располагаться после завершения (или, по крайней мере, будет выполнять большинство тех же шагов, что и утилизация).

Там нет никакой гарантии о сторонних материалах - если вы используете интерфейс к некоторой библиотеке C, которая дает вам дескрипторы, например, эти дескрипторы могут не очищаться, пока библиотека не выгружена (что, как правило, происходит только при выходе из приложения). Но достаточно часто забыть использовать Dispose или же using (или даже не знать или не заботиться о том, что определенный тип является одноразовым), что любая библиотека.net, которая не учитывает его, написана довольно плохо, IMO.

Когда объект создан, если он переопределяет Object.Finalize, система добавит его в список объектов с зарегистрированными финализаторами. Объекты в этом списке и объекты, на которые они прямо или косвенно ссылаются, не будут подлежать удалению до тех пор, пока GC.SuppressFinalize не будет вызван для них или они не будут удалены из списка иным образом. Если система замечает, что такой объект будет иметь право на исключение, если только он не существует в списке объектов, подлежащих финализации, система удалит if из списка объектов с зарегистрированными финализаторами и добавит его в список объектов, которые должны иметь свой объект Finalize. рутина называется как можно скорее. Всякий раз, когда этот последний список не является пустым, система выполняет процедуры Завершить объекты там.

Обратите внимание, что сборщик мусора на самом деле ничего не удаляет - все, что он делает, это вызывает процедуру Finalize объектов, которые зарегистрированы для финализации. Хотя многие типы объектов имеют подпрограммы Finalize, которые могут обеспечить очистку, если они ошибочно оставлены, финализация может быть сопряжена с опасностью. Объекты редко завершаются в нужное время; они часто не будут завершены до тех пор, пока они не будут отменены, и в некоторых случаях они могут быть завершены, пока их ресурсы все еще используются. Поэтому не стоит полагаться на финализаторы. Есть случаи, когда это необходимо, но они почти всегда неприглядны.

Кстати, обратите внимание, что если объекты определенного класса напрямую подписываются на события от объектов с более длительным сроком полезного использования, то ни бывшие объекты (подписчики событий), ни какие-либо объекты, на которые они имеют прямые или косвенные ссылки, не получат право на удаление или завершение пока последние объекты не делают. Хотя можно утверждать, что все классы должны очиститься после себя, если они были оставлены, для гарантии того, что подписчик события может выяснить, что он был оставлен, требуется создание и использование объектов-оболочек. Это добавит значительную сложность и ухудшит производительность в случае, если класс используется должным образом. Попытка очистить события с помощью финализатора, когда не используются объекты-оболочки, была бы бессмысленной; класс с висячими событиями не будет иметь права на коллекцию, пока издатель событий не станет подходящим, и как только это произойдет, не будет иметь значения, отписался ли предыдущий класс или нет.

Другие вопросы по тегам