Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

Либо используйте

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)

}

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

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

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

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

MemoryStream ms = new MemoryStream().Dispose

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

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

Что ж, до тех пор, пока вы используете управляемую версию ресурсов и не вызываете API-интерфейсы Windows самостоятельно, все будет в порядке.Беспокойтесь только о необходимости удаления/уничтожения ресурса, когда вы получаете IntPtr, поскольку в .NET известны «дескрипторы окон» (и многие другие вещи), а не объект.

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

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

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

Там гораздо больше подробностей ниже этот вопрос

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

При использовании утилизации или деструктора в.net необходимо понимать, что время вызова функции удаления со стороны GC не является детерминированным.Вот почему рекомендуется использовать или вызывать метод Dispose явно.

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top