Сборка мусора не уменьшает текущее использование памяти - в режиме выпуска. Зачем? - PullRequest
4 голосов
/ 20 мая 2009

Я создал быструю программу, которая должна была пройти по огромному лог-файлу (пару миллионов записей) и найти различные фрагменты внутри. Поскольку объем данных был таким огромным, мне было любопытно посмотреть на вкладку производительности диспетчера задач Windows и посмотреть, сколько ЦП и памяти используется.

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

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

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

Мысли

Ответы [ 10 ]

9 голосов
/ 20 мая 2009

Вызов GC.Collect () - это всего лишь запрос на сбор мусора, это не заказ, поэтому CLR может решить игнорировать запрос, если сочтет нужным.

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

6 голосов
/ 13 мая 2013

Есть способ. Я нашел эту статью, она на испанском, конечно, вы понимаете код, он работает, я тестировал [http://www.nerdcoder.com/c-net-forzar-liberacion-de-memoria-de-nuestras-aplicaciones/][1]

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void alzheimer()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
5 голосов
/ 20 мая 2009

Возможно, что ваши объекты все еще как-то укоренены. Вы можете попробовать использовать профилировщик памяти, чтобы увидеть, так ли это. Я обычно рекомендую SciTech .NET Memory Profiler , чтобы сделать это, но у Red-Gate также есть приличный профилировщик памяти . У SciTech и Red-Gate есть пробные версии. Также возможно использование WinDBG с SOS .

Здесь есть несколько устаревший список всех профилировщиков здесь .

4 голосов
/ 20 мая 2009

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

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

3 голосов
/ 20 мая 2009

Сборщик мусора не гарантированно запускается при вызове Collect (). Он просто помечает объект для сбора. При следующем запуске GC он «соберет» помеченный объект.

В .NET нет способа заставить GC собирать данные в определенный момент времени - если вам нужна эта функциональность, вам нужно перейти к собственному коду.

2 голосов
/ 20 мая 2009

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

1 голос
/ 04 июня 2009

, чтобы заставить GC.Collect сделать коллекцию, назовите это так GC.Collect (2); это означает, что вы просите GC выполнить полную блокировку GC для всей кучи, 2 означает поколение 2 вашей кучи.

1 голос
/ 20 мая 2009

Метод Collect не гарантирует, что вся недоступная память будет восстановлена.

0 голосов
/ 20 мая 2009

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

0 голосов
/ 20 мая 2009

Какие-нибудь объекты, используемые в вашем цикле, реализуют IDisposable?

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