Сборка мусора с помощью IDisposable - PullRequest
4 голосов
/ 27 мая 2011

Я говорил с человеком об использовании оператора ().

Он сказал, что если мы НЕ будем использовать оператор using () для чего-то вроде StreamWriter, если произойдет какое-либо исключение, ресурс НИКОГДА не будет получен.

Я понимаю использование оператора using (), но я не согласен с тем, что ресурс никогда не будет собран. Я думаю, что использование оператора () вызовет метод dispose () в конце, который может сделать коллекцию намного быстрее. Однако, даже если мы не используем using (), мы не вызываем dispose (), ресурс все равно может быть собран посредством gabage collection, хотя это может занять гораздо больше времени.

С кем вы согласны?

пс. Я знаю, что вы все говорите. Важно использовать оператор using (). Я просто хочу выяснить, будет ли ресурс определенно никогда не собираться, если мы этого не сделаем?

Ответы [ 7 ]

10 голосов
/ 27 мая 2011

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

Если StreamWriter, удерживающий дескриптор файла, получает сборщик мусора, сборщик мусора помещает объект в очередь завершения . Когда очередь финализации запускается, она вызывает финализатор объекта, а означает, что освобождает дескриптор файла.

Это все ясно? Сборщик мусора не освобождает ресурс; единственный ресурс, о котором знает сборщик мусора, это объекты в памяти. Перед освобождением объекта он завершается, поэтому сам объект знает, как освободить ресурс.

4 голосов
/ 27 мая 2011

using(x) - детерминированный паттерн.Это гарантирует, что Dispose() вызывается в реализаторе при прохождении определенной точки в потоке выполнения.GC, с другой стороны, не является детерминированным, потому что вы точно не знаете, когда объект будет фактически утилизирован.using гарантирует, что объект выполнит свой код очистки (какой бы он ни был), когда вы этого ожидаете, а не когда-нибудь в будущем.

2 голосов
/ 27 мая 2011

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

1 голос
/ 27 мая 2011

Я разговаривал с человеком об использовании оператора (). Он сказал, что если мы НЕ будем использовать оператор using () для чего-то вроде StreamWriter, если произойдет какое-либо исключение, ресурс НИКОГДА не будет собран.

Инструкция using не имеет ничего общего со сборкой мусора. Как только объект не имеет живых ссылок, он становится пригодным для сборки мусора.

Я понимаю, что нужно использовать оператор using (), но я не согласен с тем, что ресурс никогда не будет собран.

О, тогда вы правы.

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

Это может или не может сделать сбор быстрее. Обычно для метода dispose вызывается GC.SupressFinalize(object), что означает, что финализатор не будет вызываться при сборке мусора. Вместо этого объект будет просто собран. Так что это может сделать сбор быстрее.

Если вы намереваетесь сказать, что это приводит к тому, что объект будет собран немедленно, а не позже, тогда это будет неправильно. Приемлемые объекты собираются всякий раз, когда сборщик мусора доходит до него, никогда прежде, и объект становится подходящим, как только у него нет живых ссылок, на которые оператор using мало влияет. На самом деле, поскольку блок finally оператора using содержит живую ссылку, я могу представить себе сценарии, в которых он может увеличить время жизни объекта, но этот эффект не учитывается, поскольку управление временем жизни объекта не смысл использования. Детерминированное избавление от неуправляемых ресурсов является точкой использования оператора.

Однако, даже если мы не используем using (), мы не вызываем dispose (), ресурс все еще может быть собран посредством gabage collection, хотя это может занять гораздо больше времени.

Опять же, использование и удаление обычно не влияют на время жизни объекта. Он влияет только на состояние неуправляемых ресурсов (при условии, что метод Dispose реализован правильно). Вы правы, что объект все еще будет собран.

1 голос
/ 27 мая 2011

Вы должны всегда вызывать Dispose(), когда вы закончите, используя IDisposable объект. Заявление using является отличным инструментом для обеспечения соблюдения этого правила.

Цель IDisposable - позволить классам распоряжаться выделенными неуправляемыми ресурсами, которые не будут автоматически очищаться сборщиком мусора.

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

Это причина, по которой существует оператор using; он предоставляет удобный синтаксис для использования IDisposable объектов и определяет четкую область, в которой эти объекты могут использоваться.

Также обратите внимание, что сборщик мусора никогда не вызывает сам Dispose(), но также обратите внимание, что рекомендуется следовать шаблону Finalize / Dispose, как описано в MSDN . Если объект следует шаблону Finalize / Dispose, при вызове GC финализатора будет вызван Dispose().

0 голосов
/ 27 мая 2011

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

В ретроспективе StreamWriter, вероятно, должен был иметь реализацию без возможности IDisposable, но имел бы наследующий класс StreamOwningWriter, реализация которого могла бы удалять переданный поток. В качестве альтернативы он мог бы иметь параметр конструктора и свойство, указывающее, должен ли он удалять поток при вызове его собственного метода Dispose. Если бы использовался любой из этих подходов, то правильное поведение всегда состояло бы в том, чтобы вызвать Dispose на StreamWriter (и позволить «StreamWriter» (который может быть либо StreamWriter, либо StreamOwningWriter) беспокоиться о том, должен ли Dispose действительно что-то делать) ,

0 голосов
/ 27 мая 2011

с использованием по существу аналогично следующему (проверьте IL обоих, если сомневаетесь в этом):

 try
 { 
      IDisposable o = new Object();
 }
 finally
 {
      o.Dispose();
 }

Пока рассматриваемый объект реализует IDisposable, будет вызываться метод Dispose () и ресурс, ожидающий чего-то глупого, закодированного в Dispose (), будет собираться мусором. Когда? Не вопрос, на который я могу ответить.

Возможно ли, что предмет никогда не будет GCed. Ну, это никогда не бывает долго, но теоретически возможно, если оно выходит за рамки первого поколения и просто сидит там. Проблема? Нет, если память в конце концов понадобится, она будет очищена. Часто видели неправильно, как утечка памяти? Скорее всего.

...