OutOfMemoryException в совпадениях регулярных выражений при обработке больших файлов

StackOverflow https://stackoverflow.com/questions/725817

Вопрос

У меня есть журнал исключений из одной из версий производственного кода.

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.Text.RegularExpressions.Match..ctor(Regex regex, Int32 capcount, String text, Int32 begpos, Int32 len, Int32 startpos)
   at System.Text.RegularExpressions.RegexRunner.InitMatch()
   at System.Text.RegularExpressions.RegexRunner.Scan(Regex regex, String text, Int32 textbeg, Int32 textend, Int32 textstart, Int32 prevlen, Boolean quick)
   at System.Text.RegularExpressions.Regex.Run(Boolean quick, Int32 prevlen, String input, Int32 beginning, Int32 length, Int32 startat)
   at System.Text.RegularExpressions.MatchCollection.GetMatch(Int32 i)
   at System.Text.RegularExpressions.MatchEnumerator.MoveNext()

Размер данных, которые он пытается обработать, составляет около 800 КБ.

В моих локальных тестах все работает отлично.Встречали ли вы когда-нибудь подобное поведение, в чем может быть причина?

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

Мои регулярные выражения:

РЕДАКТИРОВАТЬ 2:

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

((?:( |\.\.|\.|""|'|=)[\/|\?](?:[\w#!:\.\?\+=&@!$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})*)( |\.|\.\.|""|'| ))?

РЕДАКТИРОВАТЬ

Я ошибся с местным тестом.Я загружал большую строку, затем добавлял к ней что-то, от чего у .NET Framework кружилась голова, а затем выдавал исключение OOM во время RegEx, а не во время строковых операций (или случайно, поэтому игнорируйте предыдущие вещи, которые я сказал).

Это приложение .NET Framework 2.0.

Это было полезно?

Решение

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

Механизм Regex должен хранить много информации внутри себя, и жадные совпадения могут в конечном итоге привести к тому, что Regex будет выбирать большие разделы вашей строки длиной 800 000 раз.

Там есть хорошая информация об этом здесь.

Другие советы

Судя по вашим изменениям, похоже, что ваш код может создавать строки, занимающие большие объемы памяти.Это будет означать, что хотя исключение нехватки памяти генерируется внутри кода Regex, на самом деле это не потому, что само Regex занимает слишком много памяти.Поэтому, если использование StringBuilder в вашем собственном коде решает проблему, вам следует сделать именно это.

Первое, что я бы попробовал, если это возможно для вашего приложения, — это разделить входные данные.

Можно ли прочитать файл (если входной файл является файлом) построчно, применяя таким образом регулярное выражение?

Вам следует взглянуть с Профилировщик CLR.Чтобы научиться пользоваться, может потребоваться немного времени, но оно того стоит.Это поможет вам визуализировать, сколько памяти используют ваши объекты.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top