Вопрос по сборке мусора C # .NET - PullRequest
5 голосов
/ 07 августа 2010

У меня проблема с приложением OutOfMemoryException. Мое приложение может искать слова в текстах. Когда я запускаю длительный поиск процессов для поиска около 2000 различных текстов и поиска около 2175 различных слов, приложение завершает свою работу примерно на 50% через OutOfMemoryException (после 6 часов обработки)

Я пытался найти утечку памяти. У меня есть граф объектов, как: (-> ссылки)

статический глобальный объект приложения (контроллер) -> начальный объект алгоритма -> начальный объект интеллектуального анализа текста -> объект алгоритма интеллектуального анализа текста (этот объект выполняет поиск).

Начальный объект интеллектуального анализа текста запустит метод run () - объекта алгоритма интеллектуального анализа текста в отдельном потоке.

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

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

Вот код для создания новых объектов алгоритма интеллектуального анализа текста с помощью стартера алгоритма интеллектуального анализа текста:

    private void RunSeveralAlgorithmObjects()
    {

        IEnumerable<ILexiconEntry> currentEntries = allLexiconEntries.GetGroup(intCurrentAlgorithmObject, intNumberOfAlgorithmObjectsToUse);

        algorithm.LexiconEntries = currentEntries;
        algorithm.Run();

        intCurrentAlgorithmObject++;

        for (int i = 0; i < intNumberOfAlgorithmObjectsToUse - 1; i++)
        {
            algorithm = CreateNewAlgorithmObject();
            AddAlgorithmListeners();
            algorithm.Run();
            intCurrentAlgorithmObject++;
        }

    }

    private TextMiningAlgorithm CreateNewAlgorithmObject()
    {
        TextMiningAlgorithm newAlg = new TextMiningAlgorithm();

        newAlg.SortedTermStruct = algorithm.SortedTermStruct;
        newAlg.PreprocessedSynonyms = algorithm.PreprocessedSynonyms;
        newAlg.DistanceMeasure = algorithm.DistanceMeasure;
        newAlg.HitComparerMethod = algorithm.HitComparerMethod;
        newAlg.LexiconEntries = allLexiconEntries.GetGroup(intCurrentAlgorithmObject, intNumberOfAlgorithmObjectsToUse);
        newAlg.MaxTermPercentageDeviation = algorithm.MaxTermPercentageDeviation;
        newAlg.MaxWordPercentageDeviation = algorithm.MaxWordPercentageDeviation;
        newAlg.MinWordsPercentageHit = algorithm.MinWordsPercentageHit;
        newAlg.NumberOfThreads = algorithm.NumberOfThreads;
        newAlg.PermutationType = algorithm.PermutationType;
        newAlg.RemoveStopWords = algorithm.RemoveStopWords;
        newAlg.RestrictPartialTextMatches = algorithm.RestrictPartialTextMatches;
        newAlg.Soundex = algorithm.Soundex;
        newAlg.Stemming = algorithm.Stemming;
        newAlg.StopWords = algorithm.StopWords;
        newAlg.Synonyms = algorithm.Synonyms;
        newAlg.Terms = algorithm.Terms;
        newAlg.UseSynonyms = algorithm.UseSynonyms;

        algorithm = null;

        return newAlg;
    }

Вот начало потока, который выполняет весь процесс поиска:

            // Run the algorithm in it's own thread
            Thread algorithmThread = new Thread(new ThreadStart
                (RunSeveralAlgorithmObjects));
            algorithmThread.Start();

Может ли что-то здесь помешать сборке мусора из предыдущего объекта алгоритма анализа текста?

Ответы [ 5 ]

5 голосов
/ 07 августа 2010

Я рекомендую сначала определить, что именно подтекает. Затем постулирует причину (например, ссылки в обработчиках событий).

Чтобы определить, что протекает:

  1. Включить собственную отладку для проекта. Properties -> Debug -> чек Enable unmanaged code debugging.
  2. Запустите программу. Поскольку утечка памяти, вероятно, постепенная, вам, вероятно, не нужно позволять ей работать целых 6 часов; просто дайте ему немного поработать, а затем Debug -> Break All.
  3. Откройте окно «Немедленно». Debug -> Windows -> Immediate
  4. Введите одно из следующих значений в открывшемся окне, в зависимости от того, используете ли вы 32- или 64-разрядную версию, .NET 2.0 / 3.0 / 3.5 или .NET 4.0:

    .load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll для 32-разрядных .NET 2.0-3.5

    .load C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\sos.dll для 32-разрядных .NET 4.0

    .load C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\sos.dll для 64-разрядных .NET 2.0-3.5

    .load C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\sos.dll для 64-разрядных .NET 4.0

  5. Теперь вы можете запускать команды SoS в окне Immediate. Я рекомендую проверить вывод !dumpheap -stat, и если это не определит проблему, отметьте !finalizequeue.

Примечания:

  • Запуск программы в первый раз после включения встроенной отладки может занять много времени (минут), если вы настроили VS для загрузки символов.
  • Команды отладчика, которые я рекомендовал, обе начинаются с ! (восклицательный знак).

Эти инструкции любезно предоставлены невероятной Tess от Microsoft и Марио Хьюардтом, автором Advanced .NET Debugging .

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

3 голосов
/ 07 августа 2010

1) Как я уже сказал в комментарии, если вы используете события в своем коде (AddAlgorithmListeners заставляет меня подозревать это), подписка на событие может создать «скрытую» зависимость между объектами, которые легко забываются. Эта зависимость может означать, что объект не освобожден, потому что кто-то все еще слушает одно из его событий. Убедитесь, что вы отменили подписку на все события, когда вам больше не нужно их слушать.


2) Кроме того, я хотел бы указать вам на одну (возможно, не столь не по теме) проблему с вашим кодом:

private void RunSeveralAlgorithmObjects()
{
    ...
    algorithm.LexiconEntries = currentEntries;
    // ^ when/where is algorithm initialized?

    for (...)
    {
        algorithm = CreateNewAlgorithmObject();
        ....
    }
}

algoritm уже инициализируется при вызове этого метода? В противном случае установка algorithm.LexiconEntries не будет подходящим решением. Это означает, что ваш метод зависит от некоторого внешнего состояния, которое для меня выглядит как потенциальное место для ошибок, скрывающихся в логике вашей программы.

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

PS: Если вы не хотите идти по этому пути, другая вещь, которую вы могли бы сделать, чтобы сделать свой код более последовательным, - это превратить CreateNewAlgorithmObject в void метод и переназначить * 1028. * прямо внутри этого метода.

1 голос
/ 07 августа 2010

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

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

for (int i = 0; i < intNumberOfAlgorithmObjectsToUse - 1; i++)
        {
            algorithm = CreateNewAlgorithmObject();
            AddAlgorithmListeners();
            algorithm.Run();
            RemoveAlgoritmListeners();    // See if this fixes your issue.
            intCurrentAlgorithmObject++;
        }
0 голосов
/ 07 августа 2010

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

Профилирование памяти полезно, пробовали ли вы проверять приложение с помощью профилировщика?Я нашел Red Gate полезным в прошлом (он не бесплатный, но имеет ознакомительную версию, IIRC).

0 голосов
/ 07 августа 2010

мой подозреваемый находится в AddAlgorithmListeners(); вы уверены, что удалили слушателя после завершения выполнения?

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