Ресурсы, которые необходимо вручную очистить на С#?

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

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

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

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

Какие еще ресурсы нужны для ручной очистки?

Ответ 1

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

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

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

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

Ответ 2

  • Обрабатывает внутренние структуры данных Windows.
  • Соединения с базой данных.
  • Файловые дескрипторы.
  • Сетевые подключения.
  • Ссылки COM/OLE.

Список продолжается.

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Используйте

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

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

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)

}

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

MemoryStream ms = new MemoryStream().Dispose

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

using(MemoryStream ms = new MemoryStream())
{
  ...
}

Ответ 8

Хорошо, если вы используете управляемую версию ресурсов и не вызываете сами API окон, вы должны быть в порядке. Только беспокоиться о том, что нужно удалить/уничтожить ресурс, когда вы получаете IntPtr, поскольку "обработчики окон" (и многое другое) известны в .NET, а не в объекте.

Кстати, ресурс (как и любой другой объект .NET) будет помечен для коллекции, как только вы покинете текущий контекст, поэтому, если вы создадите Brush внутри метода, он будет отмечен при выходе из него.

Ответ 9

Если это удалось (т.е. часть фреймворка), вам не нужно беспокоиться об этом. Если он реализует IDisposable, просто оберните его в блок using.

Если вы хотите использовать неуправляемые ресурсы, вам нужно прочитать финалисты и реализовать IDisposable самостоятельно.

В разделе этот вопрос гораздо больше...

Ответ 10

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

При использовании dispose или destructor in.net необходимо понимать, что время, когда функция dispose вызывается GC, не является детерминированным. Поэтому рекомендуется использовать использование или вызов ящика явно.

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

Например, SolidBrush вам нужно распоряжаться, потому что это объект GDI и живет за пределами мира .net.

Ответ 11

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

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

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

Ответ 12

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

Ответ 13

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

Ответ 14

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

Есть определенные вещи, которые необходимо очистить вручную, но это указатели, извлеченные из неуправляемых источников, таких как вызовы DLL, но ничто в .NET Framework не нуждается в этом обращении.