Это утечка памяти или нормальное поведение? - PullRequest
2 голосов
/ 14 ноября 2011

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

Чтобы обнаружить утечки памяти, я создал небольшое тестовое приложение с кнопкой new и проверкой кнопки, выполнив это:

List<WeakReference> WeakReferences = new List<WeakReference>();

private void Button_New(object sender, RoutedEventArgs e)
{
    WeakReferences.Add(new WeakReference(new ObjectUnderTest()));
    // Adding a bunch of other objects to test here
}
private void Button_Check(object sender, RoutedEventArgs e)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    int AliveCounter = 0;
    foreach (var item in WeakReferences)
    {
        if (item.IsAlive)
        {
            AliveCounter++;
            Debug.WriteLine("Object " + item.Target.GetType().ToString() + " still alive!");
        }
    }
    if (AliveCounter > 0)
    {
        MessageBox.Show(AliveCounter.ToString() + " objects still alive!");
    }
    else
    {
        MessageBox.Show("No objects alive!");
    }
}

Большинство моих тестовых объектов правильно собираются в этом сценарии, но есть несколько объектов, которые все еще живы.

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

Как вы думаете, это нормальное поведение или это утечка памяти, которую я должен устранить?

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

  • Добавление 100 объектов одним кликом по новой дает исключение памяти после примерно 650 объектов, поэтому сборщик мусора не собирается, даже если память нужна для других целей.
  • AddMemoryPressure не делает ничего более детерминированным.
  • Переключение приложения щелчком мыши не помогает, помогает только переключение с помощью ALT + TAB!?!
  • Также иногда помогает открыть новое окно в моем тестовом приложении.

1 Ответ

5 голосов
/ 14 ноября 2011

Когда вызывается GC.Collect() без аргумента GCCollectionMode, используется GCCollectionMode.Default, который в большинстве версий CLR совпадает с GCCollectionMode.Forced, что вызывает сбор данных.Чтобы убедиться, что вы форсируете коллекцию, попробуйте позвонить GC.Collect(GCCollectionMode.Forced).

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

Об общей заметкеGC решит, когда лучше всего собирать данный объект, и это поведение недетерминировано (если вы не вызываете GC.Collect(GCCollectionMode.Forced) или эквивалентный).В некоторых крайних случаях необходимо влиять на поведение сборщика мусора, но в большинстве случаев лучше оставить GC, чтобы сделать свое дело, а не беспокоиться о том, насколько эффективно это делается.Обычно это достаточно эффективно, и заставить его работать на больше эффективно, вероятно, будет довольно сложно и сложно.

...