Переполнение стека в .NET отправляет IIS на 100% использование ЦП - почему нет StackOverflowException?

У меня был код в приложении ASP.NET, запущенном на сервере Server 2008 R2 + IIS 7.5. Всякий раз, когда я загружал определенную страницу, она зависала навсегда и отправляла IIS на 100% использование ЦП. В конечном итоге я обнаружил проблему.

public string Comments
{
    get { return this.Comments; }
}

Упс - должно быть return this.Photo.Comments. Итак, мой вопрос: почему .NET не генерировал исключение StackOverflowException, но вместо этого IIS запускался на 100% -ном процессоре намного дольше, чем следовало бы. По моему опыту программирования с .NET требуется несколько секунд или меньше, чтобы получить исключение StackOverflowException при выполнении чего-то подобного выше. Итак, как он мог работать в течение почти 30 минут на IIS?

Ответы

Ответ 1

Возможно, компилятор JIT оптимизировал вызов метода на YourClass::get_Comments() (каким будет выглядеть ИЛ) и нарисует код с помощью конструкции цикла jmp (или любого другого, что было бы x64-ассемблером), потому что там любые передаваемые значения. Просто мысль.

Эта старая статья стоит посмотреть:

Jit Optimizations: Inlining (II)

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

Как есть:

Написание высокопроизводительных управляемых приложений: управляемый праймер код и JIT CLR

Я также воспроизвел это с помощью простого консольного приложения:

class Program
{
  static void Main(string[] args)
  {
    MyClass mc = new MyClass();
    string s = mc.Comments;
  }
}

public class MyClass
{
  public string  Comments
  {
    get { return this.Comments; }
  }
}

В режиме отладки с отключенными оптимизациями я получаю исключение. После включения Jit Optimisations и компиляции сборки релиза приложение запускается вечно. Это говорит о том, что, вероятно, произошло вложение в цикл.

Это также относится к С# 2.0, 3.0 и 4.0.

Ответ 2

Я попытался поместить этот код в библиотеку классов и запустить его с помощью unit test.

Сбой агента проверки MS с исключением.

Что может случиться, так это то, что вы получаете исключение stackoverflow. Это приводит к сбою пула приложений. Затем IIS вытаскивает новую копию пула приложений, и он снова разбивается...

Проверьте регистрацию событий для повторного использования/остановки пула приложений.

Ответ 3

Это происходит в разработке, а также в выпуске?

Мне жаль, что я не знаю точно, но вот мои предположения. Где-то у вас есть автоматическая повторная попытка. Таким образом, процесс операции выходит из строя из исключения StackOverflowException. Вместо того, чтобы пользователь получал сообщение, IIS повторяет новый процесс. Это продолжается и продолжается. И поэтому повторяющиеся повторы едят весь процессор.

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

Еще одна проверка, которую вы могли бы попробовать, это написать что-то, что выделяет огромный объем памяти и посмотреть, происходит ли то же самое с OutOfMemoryException. Если это так, это почти наверняка авто-повтор.