Нужно ли вызывать Dispose () для управляемых объектов? - PullRequest
28 голосов
/ 31 марта 2010

Я не могу поверить, что я все еще смущен этим, но, в любом случае, давайте, наконец, прибить это:

У меня есть класс, который переопределяет OnPaint для рисования. Чтобы ускорить процесс, я создаю ручки, кисти и т. Д. Перед конструкцией, чтобы OnPaint не нуждался в их создании и утилизации.

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

Это правильно?


Спасибо за все ответы, вопрос, безусловно, был прибит.
Я рад, что всегда был бдителен, всегда используя «использование», так что мне не нужно проходить всю мою проверку кода. Я просто хотел пояснить, что я не бессмысленный пользователь.

Кроме того, недавно у меня возникла странная ситуация, когда мне пришлось заменить блок using и вручную вызвать dispose! Я выкопаю это и создам новый вопрос.

Ответы [ 12 ]

43 голосов
/ 31 марта 2010

Это не правильно. Вам нужно избавиться от объектов, которые реализуют IDisposable. Вот почему они реализуют IDisposable - чтобы указать тот факт, что они обертывают (прямо или косвенно) неуправляемые ресурсы.

В этом случае неуправляемый ресурс является дескриптором GDI, и если вы не сможете утилизировать его, когда вы фактически с ними покончили, вы потеряете эти дескрипторы. Теперь у этих определенных объектов есть финализаторы , которые приведут к высвобождению ресурсов при включении GC, но у вас нет возможности узнать, когда это произойдет. Это может быть через 10 секунд, это может быть через 10 дней; если ваше приложение не генерирует достаточное давление памяти, чтобы GC включил и запустил финализаторы на этих кистях / ручках / шрифтах / и т. д., вы можете закончить голодать ОС ресурсов GDI до того, как GC когда-либо поймет, что происходит.

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

Мораль истории: всегда располагайте IDisposable объектами. Если ваш класс «владеет» объектами IDisposable, он должен сам реализовать IDisposable.

9 голосов
/ 31 марта 2010

Вы должны избавиться от них.

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

5 голосов
/ 31 марта 2010

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

Они, вероятно, достаточно долго, чтобы перейти в поколение №2. Сборщик мусора не очень часто выполняет сборку # 2, теперь more важно вызывать Dispose () для них. Сделайте это, переместив метод Dispose () формы из файла Designer.cs в файл form.cs и добавив вызовы Dispose.

Но сделай это правильно. Ручки и кисти - очень дешевые предметы. Создайте их, когда они вам понадобятся, в событии Paint. И используйте оператор using, чтобы они сразу же избавились. Используйте класс Секундомер, чтобы убедиться, что это на самом деле не вызывает замедления.

3 голосов
/ 31 марта 2010

Я написал компонент для построения диаграмм GDI +, который использовал множество ручек и кистей. Я создал их и разместил в блоке кода, который рисовал, и производительность никогда не была проблемой. Лучше, чем долгое время жить в ОС ОС. ИМХО.

2 голосов
/ 31 марта 2010

Профилировали ли вы это, чтобы увидеть, действительно ли создание и удаление этих объектов является проблемой? Я не думаю, что это так.

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

Если вы хотите создать их один раз, то также реализуйте IDisposable в своем классе-владельце и выполняйте итерацию Dispose для ваших собственных объектов. Нет необходимости в деструкторе (финализаторе).

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

1 голос
/ 31 марта 2010

Другие ссылаются на «использование» блоков для объектов GDI - вот пример кода:

using( var bm = new Bitmap() )
using( var brush = new Brush() )
{

   // code that uses the GDI objects goes here
   ...

} // objects are automatically disposed here, even if there's an exception

Обратите внимание, что для одного блока кода можно использовать столько строк «использования», сколько вы хотите.

Я думаю, что это хороший, чистый способ борьбы с одноразовыми объектами.

1 голос
/ 31 марта 2010

Нет, это не так. Я согласен с Аарона.

Кроме того, Microsoft рекомендует в середине 2003 г. на веб-трансляции, которую представил Дон Бокс, каждый разработчик .Net должен располагать своими собственными объектами, управляемыми или неуправляемыми, поскольку это повышает производительность кода на 20%. Если все сделано правильно, это может значительно улучшить производительность. Так что это основной навык, который каждый разработчик .net должен знать и использовать.

1 голос
/ 31 марта 2010

Нет, Pen с и Brush являются , а не полностью управляемыми объектами.

Они содержат дескриптор неуправляемого ресурса, то есть соответствующего объекта GDI в базовой графической системе. (Не уверен насчет точной терминологии здесь ...)

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

1 голос
/ 31 марта 2010

Вам действительно нужно поискать документацию по кистям, ручкам и т. Д.

Если они не используют неуправляемые ресурсы, возможно, вам не придется вызывать Dispose. Но шаблон использования / утилизации иногда «неправильно используется». В качестве примера рассмотрим инфраструктуру ASP.NET MVC. Здесь вы можете написать что-то вроде:

using(Html.BeginForm(...)){
  ///HTML input fields etc.
}

Когда вызывается Html.BeginForm(...), выводится тег FORM. Когда оператор using заканчивается, для объекта, возвращенного из Html.BeginForm(...), будет вызван Dispose. Вызов Dispose приводит к отображению конечного тега FORM. Таким образом, компилятор на самом деле обеспечит сопряжение тегов FORM, поэтому вы не забудете закрывающий тег.

1 голос
/ 31 марта 2010

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

...