Существует ли ограничение по уровню стека вызовов?
Вопрос
У меня есть пара коллег, которые просматривают какой-то плохой код в Excel VBA, задаваясь вопросом, существует ли ограничение на количество уровней в стеке вызовов
Решение
Если функция не является хвостовой рекурсивной и VBA не может ее обработать (а он не может), вы столкнетесь с переполнением стека.
В качестве простого теста я собрал следующий фрагмент:
Dim count As Integer
Sub Rec()
count = count + 1
Cells(1, 1) = count
Call Rec
End Sub
это говорит нам о том, что предел для этого составляет 4007 итераций, по крайней мере, в моей версии Excel 2007 здесь.
Другие советы
короткий ответ — да, в конечном итоге вы получите исключение переполнения стека.
Хотя не знаю, какой предел.
Я только что запустил этот макрос в Excel 2003 и получил 4775 вызовов, прежде чем получил ошибку 28 «Недостаточно места в стеке»:
Sub Macro1()
recurse (0)
End Sub
Sub recurse(level As Long)
ActiveCell.FormulaR1C1 = Str$(level)
Call recurse(level + 1)
End Sub
Я знаю старый вопрос, но я подумал, что было бы полезно получить актуальную информацию по этому вопросу, поскольку я изучал его сегодня.
Жесткий предел, по-видимому, составляет 6801 вызов для процедуры без параметров в Excel 2016.Как говорит VBA_interested, это число уменьшается с увеличением количества параметров рекурсивной процедуры.
Я провел следующие тесты в Excel 2016:
Sub RecurseStatic (без параметров) переполнился после 6801 рекурсии.
Sub Recurse1 (с 1 параметром) переполнился после 6442 рекурсий.
Sub Recurse2 (с двумя параметрами) переполнился после 6120.
Option Explicit
Sub RecurseStatic()
Static i As Long
Debug.Print i
i = i + 1
RecurseStatic
End Sub
Sub RunRecurse1()
Recurse1 0
End Sub
Sub Recurse1(i As Long)
Debug.Print i
Recurse1 i + 1
End Sub
Sub RunRecurse2()
Recurse2 0, 0
End Sub
Sub Recurse2(i As Long, j As Long)
Debug.Print i, j
Recurse2 i + 1, j + 1
End Sub
Я запустил код Андерса в Excel 2013, и результат был всего лишь 1180.Не уверен, уменьшили ли они лимит рекурсии в более новых версиях Excel, или проблема зависит от компьютера, или еще что-то в этом роде.
Редактировать:Кроме того, изменились:ActiveCell.FormulaR1C1 = Str $ (уровень) до Диапазона ("A1").FormulaR1C1 = Str $ (уровень)
И количество звонков упало до 807.Я также добавил опцию Explicit.
Потребление памяти стека.
Насколько я понимаю, стек используется для хранения параметров процедур и локальных переменных в процедурах.
Следовательно, потребление пространства стека будет пропорционально количеству рекурсивных вызовов.
Итак, необходимый размер стека примерно такой:количество рекурсивных вызовов * (размер вызываемых параметров + место для локальных переменных)