C # располагающий IDisposable - PullRequest
4 голосов
/ 28 марта 2011

Может ли кто-нибудь объяснить, что может случиться, если вы не Dispose какой-то IDisposable субъект (по using или прямому Dispose вызову) ?

Всегда ли этоприводят к утечке памяти и если да, то C# утечки памяти похожи на C++ утечки памяти, где они могут легко привести к сбою, или безопаснее с этой точки зрения песочница C#?

Спасибо.

Ответы [ 7 ]

12 голосов
/ 28 марта 2011

Это полностью зависит от рассматриваемого объекта.

Существует четыре пять причин, по которым объект может реализовать IDisposable:

  1. Он владеет собственными ресурсами.
    Если это так, он должен вызвать Dispose в своем финализаторе, поэтому все, что случится, если вы забудете утилизировать его, это то, что собственные ресурсы будут работать дольше, чем необходимо.
    Если вы создаете много таких объектов одновременно и неt для их утилизации вы можете исчерпать собственные ресурсы.

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

  3. Он имеет длительную ссылку на себя, которая не будет освобождена естественным образом (например, он обрабатывает событие static)
    Метод disposeочистил бы эту ссылку (например, отменил регистрацию обработчика события)
    Если это так, то не вызов Dispose приведет к тому, что он будет длиться вечно.

  4. Он наследует одноразовый базовый класс, напримеркак Stream или Component, но на самом деле не нужно утилизировать.(например, MemoryStream)
    Если это так, не вызывать Dispose безвредно, если только класс не изменится в будущем.

  5. Он выполняет некоторое действие в своем Disposeметод, который люди должны вызывать в выражении using (например, using (Html.BeginForm() { ... })
    Если это так, отказ от удаления объекта уничтожит всю его цель, а именно выполнение этого действия.

4 голосов
/ 28 марта 2011

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

Джо Даффи довольно четко отмечает это различие в своем посте, озаглавленном Обновление DG: удаление, завершение и управление ресурсами :

Сборщик мусора (GC) в CLR отлично справляется с управлением памятью, выделенной непосредственно объектам CLR, но явно не предназначен для работы с неуправляемой памятью и ресурсами, управляемыми ОС.

1 голос
/ 28 марта 2011

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

Это может быть проблемой, особенно с последней проблемой, если нехватка памяти недостаточна для того, чтобы GC (который запустит процесс финализации) вовремя использовал больше ресурсов.Это приводит к полезным ошибкам, так как «в GDI + произошла общая ошибка».

Плохо написанные объекты могут утечь память, если у них есть только метод Dispose и нет финализатора, но это редкость.Другая возможность состоит в том, что метод Dispose отписывается от статических событий.Это также может быть серьезной проблемой и приведет к «утечке» памяти.

1 голос
/ 28 марта 2011

Может произойти любое количество вещей, потому что класс, если он свободен, может реализовать Dispose, однако они выбирают.

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

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

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

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

1 голос
/ 28 марта 2011

Не вызов .Dispose () может привести к утечке памяти. В противном случае, не вызов Dispose () просто приведет к задержке сбора GC. В целом, эффекты будут полностью зависеть от того, какие объекты создаются ( см. SLaks для большого списка ). Реализуя IDisposable, вы берете на себя ответственность за то, чтобы, так сказать, навести порядок.

Что должна сделать реализация, это сказать GC (сборщик мусора), что она должна подавлять сбор, потому что вы позаботитесь об этом. Таким образом, когда метод Dispose () вызывается для вашего объекта IDisposable, вы должны были позаботиться об очистке - то есть вызове Dispose () для объектов в этом классе, очистке коллекций и т. Д.

И, FYI, предложение using{...} можно использовать только для объектов, реализующих IDisposable, поскольку в закрывающей скобке метод Dispose () вызывается автоматически:

using (MyDisposableObject dispObj = new MyDisposableObject())
{
    // use dispObj for some work
}    // dispObj.Dispose() is automatically called here
0 голосов
/ 29 марта 2011

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

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

0 голосов
/ 28 марта 2011

IDisposable предназначен для обёртывания неуправляемых ресурсов (т. Е. Не памяти .NET). Поэтому, если вы не утилизируете их, вы потеряете такие вещи, как открытые соединения с базой данных, дескрипторы окон, дескрипторы файлов и т. Д. В зависимости от того, какой тип IDisposable вы не можете утилизировать.

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

...