Ответ 1
Используете ли вы экземпляры Regex или статические методы Regex, которые принимают строковый шаблон? В соответствии с этим сообщением экземпляры 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 был использован в более поздней точке, вероятно, это будет обработка другого большого отчета. Это относительно значительная проблема, и просто чувствует себя грязно.
Все, что сказал, я нашел несколько вариантов того, как разрешить или хотя бы обойти этот сценарий. Я позволю сообществу ответить первым, и если ни один из участников не выйдет вперед, я восполню любые пробелы через день или два.
Используете ли вы экземпляры Regex или статические методы Regex, которые принимают строковый шаблон? В соответствии с этим сообщением экземпляры Regex не участвуют в кешировании.
Попробуйте переключиться на скомпилированное Regex - создание экземпляра займет больше времени, но, возможно, не будет подвержено этой нечетной утечке.
Подробнее см. http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regexoptions%28v=VS.100%29.aspx.
Или, не удерживайте экземпляр Regex дольше, чем вам нужно, - создайте новый для каждого вызова отчета.