Ресурсы, которые должны быть очищены вручную в C #? - PullRequest
11 голосов
/ 22 сентября 2008

Какие ресурсы необходимо очистить вручную в C # и каковы последствия этого не делать?

Например, скажем, у меня есть следующий код:

myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
// Use Brush

Если я не очищу кисть, используя метод dispose, я предполагаю, что сборщик мусора освобождает память, используемую при завершении программы? Это правильно?

Какие еще ресурсы мне нужно очистить вручную?

Ответы [ 14 ]

7 голосов
/ 22 сентября 2008

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

В общем, если у чего-то есть метод Dispose, вы должны вызывать его, когда закончите, или, если можете, заключить его в оператор using:

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
    // use myBrush
}
7 голосов
/ 22 сентября 2008
  • Дескрипторы внутренних структур данных Windows.
  • Соединения с базой данных.
  • Файловые дескрипторы.
  • Сетевые подключения.
  • COM / OLE ссылки.

Список можно продолжить.

Важно позвонить Dispose или, что еще лучше, использовать шаблон using.

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
    // use myBrush
}

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

В случае System.Drawing.Brush Windows будет сохранять внутренние структуры окон для кисти, загруженной в память, пока все программы не освободят свой дескриптор.

3 голосов
/ 23 сентября 2008

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

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

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

Либо использовать

using (new DisposableThing...
{
    ...
}

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

class MyClass : IDisposable
{
    private IDisposable disposableThing;

    public void DoStuffThatRequiresHavingAReferenceToDisposableThing() { ... }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    //etc... (see IDisposable on msdn)

}

2 голосов
/ 22 сентября 2008

Как правило, все, что реализует IDisposable, должно заставить вас остановиться и исследовать ресурс, который вы используете.

ГХ происходит только при нехватке памяти, поэтому вы не можете предсказать, когда. Хотя выгрузка AppDomain непременно вызовет его.

1 голос
/ 23 сентября 2008

Уловка, которую я использую, когда не могу вспомнить, является ли данный объект одноразовым ресурсом, состоит в том, чтобы набрать «.Dispose» (самое большее!) После объявления, чтобы Intellisense проверил меня:

MemoryStream ms = new MemoryStream().Dispose

Затем удалите .Dispose и используйте директиву using ():

using(MemoryStream ms = new MemoryStream())
{
  ...
}
1 голос
/ 23 сентября 2008

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

1 голос
/ 23 сентября 2008

Технически все, что наследуется от IDisposable, должно быть предварительно удалено. Вы можете использовать выражение «using», чтобы упростить задачу.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Иногда вы можете увидеть непоследовательное использование IDisposable производных объектов в примере кода документации, а также код, который генерируется инструментами (то есть Visual Studio).

Что хорошо в IDisposable, так это то, что он дает возможность заблаговременно высвобождать базовый неуправляемый ресурс. Иногда вы действительно хотите сделать это - например, подумайте о сетевых подключениях и файловых ресурсах.

0 голосов
/ 02 декабря 2010

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

0 голосов
/ 23 сентября 2008

Осторожно: объекты, которые выглядят малыми для GC, но не ... В API SharePoint, например, объект SPWeb занимает небольшую площадь, насколько это касается GC, и поэтому будет иметь низкий приоритет для сбора, но он действительно захватил кучу памяти (в куче, я верю), о которой GC не знает. Вы столкнетесь с некоторыми забавными проблемами с памятью, если, например, вы проповедуете целую кучу таких вещей, всегда не забывайте использовать их или избавляться!

0 голосов
/ 23 сентября 2008

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

Одним из больших преимуществ C # по сравнению с C / C ++ является то, что вам не нужно заботиться об освобождении выделенных объектов (по крайней мере, в большинстве случаев); gc делает это, когда решает среда выполнения (различные стратегии, когда / как это сделать).

О многих ресурсах не заботится gc: file, ресурсы, связанные с потоками (блокировки), сетевые подключения и т. Д ...

...