Что на самом деле означает переполнение стека в мире .Net? - PullRequest
1 голос
/ 01 апреля 2011

Что на самом деле означает переполнение стека в мире .Net сбора мусора?

Ответы [ 7 ]

11 голосов
/ 01 апреля 2011

Точно так же, как и везде - вы взорвали стек, обычно потому, что вы плохо повторили. Например:

public int Foo(int x)
{
    return Foo(x + 1);
}

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

Это не имеет ничего общего с сборкой мусора.

3 голосов
/ 01 апреля 2011

Переполнение стека и сборка мусора являются по существу ортогональными понятиями: стек против кучи. Задача сборщика мусора - вернуть недостижимые объекты, которые живут в куче. Переполнение стека происходит, когда стек выполнения превышает предел, допустимый текущим потоком. Все элементы в стеке по определению достижимы, поэтому сборщик мусора ничего не может сделать для «очистки» стека

2 голосов
/ 01 апреля 2011

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

1 голос
/ 01 апреля 2011

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

Самое первое, что поддерживает стек процессора, - это вызов подпрограмм. Инструкция CALL помещает значение указателя инструкции в стек и переходит к фрагменту кода. Это завершается инструкцией RET, он возвращает значение указателя инструкции из стека, и выполнение продолжается там, где оно было прервано, по инструкции после инструкции CALL. Вы узнаете это как метод на языках .NET.

Подпрограмма часто должна работать с переменными, переданными из вызывающего кода. На уровне процессора это работает путем помещения их значения в стек с помощью инструкции PUSH. Затем вызываемая подпрограмма считывает их значение путем индексации стека в известном месте. Вы узнаете это как метод параметр в языках .NET.

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

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

Проблема возникает, когда метод вызывает другой метод, который вызывает другой метод, и так далее. Каждый метод занимает место. Это не может продолжаться вечно, в конце концов, процессору не хватает места в стеке. Это Большой Kaboom, StackOverflowException в .NET. По своей сути это ошибка операционной системы низкого уровня. Восстановление из SOE невозможно, основной механизм запуска кода на процессоре неисправен. Вы не можете поймать исключение, ваша программа умирает мгновенной смертью.

1 голос
/ 01 апреля 2011

.NET по-прежнему использует стек для размещения локальных переменных (и остальной части стекового фрейма), поэтому это означает почти то же самое, что и всегда.Единственное отличие состоит в том, что он выдает исключение, которое может быть обнаружено в версиях .NET ниже 2.0.Однако сложно написать код, который корректно восстанавливается после этого состояния.Таким образом, текущие версии больше не позволяют ловить его.Однако переполнение стека не вызывает неопределенного поведения в любой версии .NET.

1 голос
/ 01 апреля 2011

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

По сути, начиная с .NET Framework 2.0, объект StackOverflowException не может быть перехвачен блоком try-catch, и соответствующий процесс завершается по умолчанию. Следовательно, пользователям рекомендуется писать свой код для обнаружения и предотвращения переполнения стека. Например, если ваше приложение зависит от рекурсии, используйте счетчик или условие состояния для завершения рекурсивного цикла.

0 голосов
/ 01 апреля 2011

Довольно распространенной ошибкой в ​​.NET является что-то вроде:

private int someProperty;
public int SomeProperty
{
    get { return SomeProperty; }
    set { SomeProperty = value; }
}

Что даст вам исключение StackOverflowException. Единственная подсказка - предупреждение о том, что someProperty никогда не используется.

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