Вопрос по сборщику мусора в .NET (утечка памяти) - PullRequest
7 голосов
/ 14 ноября 2009

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

Я привык к кодированию на C, где вы должны free() все. В C ++ /. NET я читал о сборщике мусора. Из того, что я понимаю, когда экземпляр больше не используется (в области видимости объекта), он освобождается сборщиком мусора.

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

Я пытался найти это в Google, но я не нашел ничего хорошего для новичка.

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

Ответы [ 7 ]

11 голосов
/ 14 ноября 2009

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

То, что мы обычно называем утечкой памяти в .NET, больше похоже на:

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

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

Здесь, я думаю, я приведу более сложный ответ только для пояснения.

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

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

Если вы действительно хотите увидеть, как вы освобождаете форму (когда вы выходите из области видимости и больше не ссылаетесь на нее), вы можете позвонить GC.Collect(). Делайте это только для тестирования, крайне неразумно звонить в Collect, за исключением очень немногих случаев, когда вы точно знаете, что делаете, и какие последствия это будет иметь.

Немного подробнее о методе Dispose интерфейса IDispose.

Утилизация не является деструктором обычным способом C ++, она вообще не деструктор. Утилизация - это способ детерминистически избавиться от неуправляемых объектов . Пример. Предположим, вы вызываете внешнюю COM-библиотеку, которая выделяет 1 ГБ памяти из-за того, что она делает. Если у вас нет команды Dispose, память будет сидеть там, тратя пространство до тех пор, пока GC не начнет сборку и не освободит неуправляемую память, вызвав фактический деструктор объекта. Поэтому, если вы хотите сразу освободить память, вам нужно вызвать метод Dispose, но вы не обязаны это делать.

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

8 голосов
/ 14 ноября 2009

Что привело вас к выводу, что существуют утечки памяти? При сборке мусора нет гарантии, что память освобождается немедленно , и в общем случае сборщик мусора не включается, пока память вашего процесса не достигнет некоторого порога или не будет исчерпана доступная куча. (Точная эвристика сложна и не важна.) Поэтому тот факт, что память вашего процесса увеличивается и не падает, не обязательно означает, что есть ошибка. Возможно, GC еще не успел очистить ваш процесс.

Кроме того, вы уверены , что нет ссылок на ваши объекты? Возможно, у вас есть ссылки, о которых вы не знаете. Большинство утечек памяти в приложениях .NET вызвано тем, что люди не понимают, что на их память все еще ссылаются.

7 голосов
/ 14 ноября 2009

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

См. Как: использовать CLR Profiler .

4 голосов
/ 14 ноября 2009

Я добавляю это как ответ, а не как комментарий к вопросу, но это продолжение вопроса, заданного ФП в комментарии: с использованием оператора в MSDN. IDisposable интерфейс в MSDN.

В этом суть проблемы: то, к чему вы привыкли, деструкторы объектов исчезли.Все, что вам сказали о том, как правильно кодировать, кричит из вашего подсознания, говоря, что это не может быть правдой, а если это правда, то это неправильно и ужасно.Это очень разные;трудно вспомнить, насколько я действительно презирал это сначала (я был гордым разработчиком C ++).

Я лично обещаю вам: все будет хорошо!

Вот еще одна хорошая вещь для чтения: Деструкторы и финализаторы в Visual C ++ .

3 голосов
/ 14 ноября 2009

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

1 голос
/ 15 ноября 2009

Если вы просто хотите выяснить, есть ли у вас утечка памяти или нет, взгляните на perfmon , который поставляется с вашей копией windows:

В частности, счетчик памяти .NET CLR байт во всех кучах , если это число постоянно растет, у вас есть утечка.

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

Как только вы подтвердите, что произошла утечка, вы можете присоединиться с помощью windbg и использовать расширения sos , чтобы определить, что происходит утечка.

Если вы можете позволить себе потратить несколько долларов, взгляните на .NET Memory Profiler .

0 голосов
/ 14 ноября 2009

Существуют бесплатные инструменты для просмотра управляемой кучи в .Net, с использованием расширений SOSEX до WinDBG и SOS , возможно запускать программа, приостановите ее, затем посмотрите, какие объекты существуют в стеке и (что более важно), какие другие объекты содержат ссылки на них (корни), что будет препятствовать GC собирать их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...