C # Простой код сборки мусора не работает

#c# #garbage-collection

#c# #сбор мусора

Вопрос:

У меня есть простое приложение WPF, которое выделяет память, очищает ее и взаимодействует со сборщиком мусора. К сожалению, я никогда не вижу, чтобы собранный мусор автоматически очищал память. Например, скажем, я нажимаю кнопку Alloc 10 раз, она выделяет гигабайт, затем, если я нажимаю кнопку New, выделенная память не уменьшается. Однако, если я принудительно соберу мусор с помощью GC.Сбор (кнопка GC) освобождает память. Я включил большие коллекции с gcAllowVeryLargeObjects, для которых установлено значение true, так как я хотел бы протестировать использование более 2 гигабайт. Есть идеи, как я могу заставить сборщик мусора автоматически собирать и освобождать память?

Простой фрагмент кода:

 List<byte[]> m_allocs = new List<byte[]>();

private void AllocClick(object sender, RoutedEventArgs e)
{
  int oneHundredMegsAsBytes = 100000000;
  byte[] array = new byte[oneHundredMegsAsBytes];
  Array.Clear(array, 0, oneHundredMegsAsBytes);
  m_allocs.Add(array);
}

private void NewClick(object sender, RoutedEventArgs e)
{
  m_allocs = new List<byte[]>();
}

private void ClearClick(object sender, RoutedEventArgs e)
{
  m_allocs.Clear();
}

private void GCClick(object sender, RoutedEventArgs e)
{
  GC.Collect();
  GC.WaitForPendingFinalizers();
  GC.Collect();
}
  

Комментарии:

1. Если в ОС все еще достаточно свободной памяти, GC пытается не запускаться, потому что в этом нет необходимости. Однако Array.Clear() в вашем примере ничего не делается — он просто устанавливает содержимое массива в значение по умолчанию для типа элемента массива; в вашем случае ноль — но массив уже содержит все нули. Это не изменяет размер массива.

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

3. И имейте в виду, что вся причина существования GC заключается в том, чтобы позволить разработчикам не беспокоиться об управлении памятью. Вам не нужно тестировать GC, он действительно работает.

Ответ №1:

Вы этого не делаете.

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

Вы этого не хотите.

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

Однако…

Вы могли бы изменить процентное значение с большим объемом памяти на меньшее значение, что сделает GC намного более агрессивным, намного раньше. Вероятно, это принесет вам больше вреда, чем пользы.

Ответ №2:

При экспериментировании на основе новой информации из ваших комментариев я нашел решение. Если я нажимаю alloc много раз, например, до использования 10 гигабайт, затем нажимаю очистить и продолжаю выделять больше, в конечном итоге использование памяти снижается до более низкого значения, например, 2 гигабайта.

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