Помогите разобраться с ошибкой

310
28 января 2017, 08:17

Есть объект, наследованный от IEnumerable. StackOverflowException возникает в методе MoveNext этого класса, на строчке с Regex. Само регулярное выражение ищет совпадения текста в файлах. Что примечательно, так это то, что на Win 10 x64 c .Net 4.6 все работает, ошибка возникает на Win 7 x64 c .Net 4.0. У меня есть 2 предположения почему так происходит. Первое, возможно из-за отличий реализации метода Regex в .Net 4.0 и .Net 4.6 Regex занимает больше памяти в stack и поэтому падает exception. Второе предположение, это то, что может быть размер стека в Win10 отличается от размера в Win7? В следствии чего у меня возникают вопросы, как проверить текущий размер стека? Как проверить доступный размер стека? И какие еще могут быть причины данной ошибки? Количество файлов в IEnumerable, по которым идет поиск 2760 (_objEnumerator.Count), каждый файл подгружается заранее и храниться в качестве строки в этом самом IEnumerable. Ниже приведен примерный код:

private class MyEnumerator : IEnumerable
{
    public bool MoveNext()
    {
        if (_objEnumerator == null)
        {
            _objEnumerator = _objects.GetEnumerator();
        }
        Match m;
        if (_current == null)
        {
            if (!_objEnumerator.MoveNext())
                return false;
            m = _regex.Match((_objEnumerator.Current).Text); // (_objEnumerator.Current).Text хранит  текст файла, ошибка падает в этой строчке
            }           
            if (m.Success)
            {
               // код выдающий результат
               return true;
            }
            else
            {
               _current = null;
               return MoveNext();
            }
        }
    }
Answer 1

Проблема, думаю, именно из-за рекурсии (глубина 2700, это много). В .NET начиная, кажется, с 4.5, перешли на новый JIT-компилятор, который умеет определять хвостовую рекурсию, и производить вызов tailcall вместо нормального рекурсивного вызова. В результате стек не забивается.

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

Важное уточнение: я попробовал код, аналогичный вашему, и он не генерирует в VS 2015/.NET 4.5/x64/Release хвостовой вызов. Значит, ваша проблема может быть не в этом. Я попробую расследовать причину дальше.

READ ALSO
автоматическое определение диапазона ip-адресов [требует правки]

автоматическое определение диапазона ip-адресов [требует правки]

Здравствуйте! Такая задача: ipconfig - автоматическое определение ip-адресов, как это реализовать на c#? Те

277
Сохранение Id с помощью Entity Framework

Сохранение Id с помощью Entity Framework

У меня есть EF 6x, несколько сущностей и с полем Id у каждой (типа Guid), которые сконфигурены как

325
Proxy Laravel, как?

Proxy Laravel, как?

От пользователя приходит запрос с адресом (uri) и дополнительными даннымиВ моих задачах стоит отправить get запрос на данный адрес с использованием...

371