.NET RegEx "Утечка памяти"

Недавно я изучил некоторые "утечки памяти".NET(т.е. неожиданные, затянутые объекты, связанные с GC) в приложении WinForms. После загрузки и последующего закрытия огромного отчета использование памяти не упало, как ожидалось, даже после нескольких коллекций gen2. Предполагая, что элемент управления отчетами остался в живых с помощью обработчика случайных событий, я взломал открытый WinDbg, чтобы увидеть, что происходит...

Используя WinDbg, команда !dumpheap -stat сообщила, что большой объем памяти был потреблен экземплярами строк. Дальнейшее уточнение этого с помощью команды !dumpheap -type System.String я нашел виновника, 90 МБ строку, используемую для отчета, по адресу 03be7930. Последний шаг состоял в том, чтобы вызвать !gcroot 03be7930, чтобы увидеть, какой объект поддерживал его.

Мои ожидания были неправильными - это был не обработчик обработанных событий, зависающий над элементом управления отчетами (и строкой отчета), но вместо этого он поддерживался экземпляром System.Text.RegularExpressions.RegexInterpreter, который сам является потомком System.Text.RegularExpressions.CachedCodeEntry. Теперь кэширование регулярных выражений (несколько) общеизвестно, поскольку это помогает уменьшить накладные расходы при необходимости перекомпилировать Regex каждый раз, когда он используется. Но чем же это связано с сохранением моей струны?

На основе анализа с использованием Reflector выясняется, что входная строка сохраняется в RegexInterpreter всякий раз, когда вызывается метод Regex. RegexInterpreter держится за эту строковую ссылку до тех пор, пока в нее не будет добавлена ​​новая строка путем последующего вызова метода Regex. Я бы ожидал подобного поведения, повесив экземпляры Regex.Match и, возможно, другие. Цепочка выглядит примерно так:

  • Regex.Split, Regex.Match, Regex.Replace и т.д.
    • Regex.Run
      • RegexScanner.Scan(RegexScanner - базовый класс, RegexInterpreter - это подкласс, описанный выше).

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

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

Ответы

Ответ 1

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

Ответ 2

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

Подробнее см. http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regexoptions%28v=VS.100%29.aspx.

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