C # одноразовый вопрос - PullRequest
3 голосов
/ 29 апреля 2011

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

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

Ответы [ 6 ]

16 голосов
/ 29 апреля 2011

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

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

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

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

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

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

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

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

3 голосов
/ 29 апреля 2011

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

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

2 голосов
/ 29 апреля 2011

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

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

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

1 голос
/ 29 апреля 2011

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

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

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

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

0 голосов
/ 30 апреля 2011

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

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

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

0 голосов
/ 29 апреля 2011

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

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

...