.NET RegEx "Утечка памяти" расследование - PullRequest
14 голосов
/ 29 апреля 2010

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

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

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

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

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

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

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

Ответы [ 2 ]

8 голосов
/ 29 апреля 2010

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

0 голосов
/ 29 апреля 2010

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

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

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

...