Метод .dispose () вообще что-нибудь делает? - PullRequest
6 голосов
/ 08 января 2010

Я экспериментировал со способами устранения некоторых утечек памяти в моем приложении на днях, когда понял, что практически ничего не знаю об очистке своих ресурсов. Я провел некоторое исследование и надеялся, что простой вызов .dispose () решит все мои проблемы. У нас есть таблица в нашей базе данных, которая содержит около 65 000 записей. Очевидно, что когда я заполняю свой набор данных из адаптера данных, использование памяти может быть довольно высоким. Когда я вызвал метод dispose для набора данных, я с удивлением обнаружил, что НИЧЕГО из памяти не освободилось. Почему это случилось? Очистка набора данных также не помогает.

Ответы [ 4 ]

26 голосов
/ 08 января 2010

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

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

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

Используется для очистки ресурсов, управляемых объектом.

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

У вас действительно есть проблема с памятью, или вы просто смотрите на использование памяти в диспетчере задач или аналогичном и говорите "это немного завышено"??

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

Позвольте мне объяснить, что я имею в виду под "бегать реже".

Если у вас 8 ГБ памяти на вашем компьютере и работают только Windows и Блокнот, большая часть этой памяти будет доступна. Теперь, когда вы запускаете свою программу, даже если она загружает второстепенные блоки данных в память, вы можете продолжать делать это в течение длительного времени, и использование памяти будет постоянно расти. Точно, когда GC включится и попытается уменьшить объем памяти, я не знаю, но я почти гарантирую вам, что вы удивитесь, почему он так высок.

Давайте просто ради аргумента скажем, что ваша программа в конечном итоге будет использовать 2 ГБ памяти.

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

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

4 голосов
/ 08 января 2010

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

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

3 голосов
/ 08 января 2010

Я собираюсь указать на кое-что здесь, что не было явно упомянуто: вызов Dispose() очистит (освободит) неуправляемые ресурсы, только если разработчик компонента закодировал это.

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

1 голос
/ 04 марта 2013

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

Во многих случаях, когда объект "Джордж" сообщает внешнему объекту "Джо", что его услуги больше не нужны, Джордж должен знать, что его услуги больше не нужны. Есть два обычных способа, с помощью которых это может происходить в .NET: финализация и IDIsposable.

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

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

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

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

...