Распоряжение ресурсами в .NET - PullRequest
5 голосов
/ 09 июля 2010

У меня глупый вопрос, но я хочу услышать сообщество здесь.

Так вот мой код:

using (FtpWebResponse response = (FtpWebResponse)request.GetResponse()) 
{ 
      return true; 
} 

Мой вопрос, отличается ли он от:*

(FtpWebResponse)request.GetResponse();
return true;

Какой из них лучше вообще?какой с точки зрения GC и почему?

Ответы [ 5 ]

11 голосов
/ 09 июля 2010

Первый лучше, но не с точки зрения GC. WebResponse реализует IDisposable, потому что у него есть ресурсы, которые должны быть освобождены, такие как сетевые подключения, потоки памяти и т. Д. IDisposable на месте, потому что вы, как потребитель, знаете, когда вы закончили с объектом, и вызываете Dispose до уведомите класс, с которым вы закончили, и он может убирать за собой.

Шаблон using на самом деле просто вызывает Dispose под капотом. Например. Ваш первый пример фактически скомпилирован так:

FtpWebResponse response = (FtpWebResponse)request.GetResponse()
try
{
}
finally
{
    ((IDisposable)response).Dispose();
}
return true;

Это отдельно от сборщика мусора. Класс также может очищать ресурсы в финализаторе, который вызывается из GC, но вы не должны полагаться на это по двум причинам:

  1. Может пройти очень много времени, прежде чем GC, наконец, придет в себя, что означает, что эти ресурсы сидят там и расходуются без веской причины.
  2. В любом случае, он может не очистить ресурсы в финализаторе
7 голосов
/ 09 июля 2010

Первый лучше.

Разница в том, что оператор using вызовет dispose для обернутого в него объекта. Он правильно распорядится удерживаемыми ресурсами.

С MSDN , оператор использования:

Предоставляет удобный синтаксис, обеспечивающий правильное использование IDisposable объектов.

4 голосов
/ 09 июля 2010

Я ценю, что вы не заинтересованы в ответе.Однако объект ответа был создан, инициализирован и возвращен вашему коду независимо от того, хотите вы этого или нет.Если вы не утилизируете его, он будет зависать от потребляемых ресурсов до тех пор, пока GC в конце концов не дойдет до его завершения.

2 голосов
/ 09 июля 2010

Я согласен с тем, что говорили другие, но если у вас есть такая ненависть к синтаксису using (), вы можете сделать:

((IDisposable)request.GetResponse()).Dispose();
return true; 
1 голос
/ 09 июля 2010

GC не заботится ни о чем, кроме памяти, поэтому, если у вас много памяти и вы не занимаете ее много, может пройти очень много времени, пока она не выполнит GC. В течение всего этого времени неуправляемые ресурсы, такие как сетевые соединения, файловые дескрипторы, соединения с базой данных, графические дескрипторы и т. Д., Остаются связанными объектами, ожидающими получения GC. Это может привести к тому, что вам не хватит этих ресурсов, и сборщик мусора не заметит, потому что он не контролирует неуправляемые ресурсы.

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

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

...