Разработка и Конфигурация · 12 мин
Переполнение стека встроенного языка на сервере 1С: что это и как исправить
Что означает ошибка переполнения стека встроенного языка на сервере 1С, почему возникает рекурсия и переполнение стека вызовов, как найти и исправить проблему в коде.
Ошибка «Переполнение стека встроенного языка на сервере» — одно из самых характерных сообщений, с которым сталкиваются разработчики 1С. Она означает, что программный код на встроенном языке 1С выполнил слишком много вложенных вызовов процедур и функций, и отведённая под стек вызовов память исчерпана. Чаще всего причина — бесконечная или слишком глубокая рекурсия, когда процедура прямо или косвенно вызывает саму себя без условия выхода.
Стек вызовов — это область памяти, в которой платформа хранит информацию о каждом незавершённом вызове: адрес возврата, локальные переменные, параметры. Каждый новый вызов процедуры или функции добавляет в стек запись, а завершение — удаляет её. Если вызовы накапливаются быстрее, чем завершаются, стек переполняется, и сервер 1С аварийно прерывает выполнение кода с соответствующим сообщением.
Ошибка проявляется именно «на сервере», когда проблемный код выполняется в серверном контексте — в серверных процедурах и функциях общих модулей, модулей объектов, обработчиках событий, фоновых заданиях и регламентных операциях. В клиент-серверном режиме работы сообщение приходит пользователю от кластера серверов 1С, а сам сбой фиксируется в технологическом журнале и журнале регистрации.
Что такое стек вызовов и почему он переполняется
Стек вызовов работает по принципу «последним пришёл — первым ушёл». Когда процедура А вызывает функцию Б, платформа запоминает, куда вернуться после завершения Б, и сохраняет её локальные данные. Если Б вызывает В, а В — снова А, цепочка растёт. Пока глубина вложенности разумна, всё работает; при тысячах или десятках тысяч вложенных вызовов память стека заканчивается.
Важно понимать: переполнение стека — это не утечка памяти и не нехватка оперативной памяти сервера в целом. Это ограничение именно на глубину вложенных вызовов внутри одного потока выполнения кода. Даже на сервере с большим объёмом ОЗУ бесконечная рекурсия гарантированно приведёт к этой ошибке.
Размер стека для потоков исполнения кода ограничен и не масштабируется произвольно. Поэтому алгоритмы, которые корректно работают на маленьких данных, могут падать на больших: например, рекурсивный обход дерева подчинённых элементов справочника нормально отработает на десяти уровнях вложенности, но упадёт на реальной базе с сотнями уровней.
Типичные причины ошибки
Самая распространённая причина — рекурсия без корректного условия выхода. Разработчик пишет процедуру обхода дерева, но забывает проверку на конец ветки, либо условие выхода никогда не наступает из-за особенностей данных: циклическая ссылка в иерархии, элемент, чей родитель указывает сам на себя или на потомка.
Вторая группа причин — косвенная рекурсия через обработчики событий. Классический сценарий: в обработчике «ПриЗаписи» документа код изменяет и записывает тот же или связанный объект, что снова инициирует «ПриЗаписи», и цепочка повторяется до переполнения стека. Аналогично зацикливаются подписки на события, когда одна подписка вызывает действие, перехватываемое другой подпиской.
Третья группа — взаимные вызовы между модулями: функция из общего модуля А вызывает функцию модуля Б, которая при определённых условиях снова обращается к А. Внешне код выглядит линейным, и зацикливание проявляется только при конкретном сочетании данных.
Проверить условия завершения рекурсивной процедуры
Ищите запись объекта внутри его собственных обработчиков
Проверьте иерархию справочника на замкнутые петли
Трассируйте стек вызовов в технологическом журнале
Как выглядит ошибка и где искать её следы
Пользователь видит сообщение вида «Переполнение стека встроенного языка на сервере» с указанием модуля и строки, хотя указанная строка — это лишь место, где стек исчерпался, а не обязательно источник проблемы. Реальный виновник может находиться выше по цепочке вызовов.
Основной инструмент диагностики — технологический журнал сервера 1С с включёнными событиями EXCP и, при необходимости, CALL для трассировки вызовов. В событии исключения фиксируется стек вызовов на момент сбоя: по нему видно повторяющуюся последовательность процедур, которая и есть зацикленная цепочка.
Дополнительно стоит проверить журнал регистрации в конфигураторе: там ошибка фиксируется с привязкой к пользователю, сеансу и операции, что помогает воспроизвести ситуацию. Если ошибка возникает в фоновом задании, смотрите состояние и сообщения самого задания.
Как найти зацикленный вызов: порядок действий
Начните с воспроизведения: определите, на каких данных и при какой операции возникает ошибка. Если сбой происходит только на конкретном элементе справочника или документе, с высокой вероятностью проблема в данных — например, циклическая иерархия.
Затем включите технологический журнал на время воспроизведения, получите стек вызовов и найдите в нём периодически повторяющуюся последовательность модулей и процедур. Эта последовательность — цикл, который нужно разорвать.
- 1Воспроизведите ошибку и зафиксируйте операцию и данные, на которых она возникает
- 2Включите технологический журнал с событием EXCP и повторите операцию
- 3Откройте стек вызовов в событии исключения и найдите повторяющуюся цепочку процедур
- 4Проверьте найденную процедуру: есть ли условие выхода и наступает ли оно на реальных данных
- 5Проверьте данные на циклические ссылки (родитель = потомок, объект ссылается сам на себя)
- 6Исправьте код или данные и повторите операцию для проверки
Если технологический журнал настроить нельзя, используйте отладку: поставьте точку останова в подозреваемой процедуре и наблюдайте, сколько раз и с какими параметрами она вызывается. Быстрое накопление вызовов с одинаковыми параметрами — верный признак зацикливания.
Способы исправления
Первый и главный способ — добавить или исправить условие выхода из рекурсии. Убедитесь, что на каждой итерации алгоритм приближается к завершению: обрабатываемое множество элементов уменьшается, уровень вложенности ограничен, уже посещённые узлы помечаются и пропускаются.
Для защиты от циклических данных добавьте контроль посещённых элементов: перед обработкой узла проверяйте, нет ли его в соответствии или массиве уже обработанных. Это стандартная защита от замкнутых петель в иерархии.
Если глубина вложенности принципиально велика, замените рекурсию на итеративный алгоритм с явным стеком в виде массива: вместо вызова самой себя процедура кладёт элементы в массив и обрабатывает их в цикле. Такой подход не ограничен размером стека вызовов и безопасен на любых данных.
Для зацикливания в обработчиках событий используйте признак повторного входа: например, параметр «Загрузка» при записи, собственный флаг в дополнительных свойствах объекта или проверку, изменились ли фактически данные, прежде чем инициировать новую запись.
Сравнение вариантов
Подходит, когда глубина вложенности ограничена и предсказуема; не защищает от циклических данных
Обязателен при обходе иерархий с возможными циклическими ссылками; немного замедляет обход
Самый надёжный вариант для большой глубины; требует переработки алгоритма
Решает зацикливание ПриЗаписи и подписок; нужно аккуратно сбрасывать флаг
Профилактика и проверка результата
После исправления проверьте операцию на тех же данных, где возникал сбой, и на заведомо «тяжёлых» данных: максимально глубокой ветке иерархии, большом документе. Убедитесь, что операция завершается за разумное время и результат корректен, а не просто не падает.
Для профилактики при разработке рекурсивных алгоритмов сразу закладывайте ограничение глубины или контроль посещённых узлов, а в обработчиках записи — защиту от повторного входа. Полезно также тестировать обход иерархий на искусственно созданной циклической ссылке: корректный код должен завершиться без ошибки.
Как проверить результат
Завершается без ошибки и даёт корректный результат
Ошибка повторяется или результат неполный
Обход выполняется за разумное время
Операция зависает или падает на большой глубине
Код обнаруживает петлю и завершается
Снова переполнение стека
Нет повторяющихся цепочек вызовов
В стеке виден повторяющийся цикл
Типичные ошибки при диагностике
Отдельная ошибка — считать проблему инфраструктурной. Переполнение стека встроенного языка практически всегда вызвано логикой кода или данными, а не настройками сервера. Изменение параметров кластера, перезапуск служб и добавление памяти не устраняют причину.
Когда обращаться к специалистам
Самостоятельное исправление безопасно, если у вас есть доступ к конфигуратору, копия базы для экспериментов и понимание алгоритма. Изменения в типовой конфигурации делайте с учётом последующих обновлений: правки в типовых модулях усложнят обновление, предпочтительны расширения конфигурации.
Если зацикливание происходит в типовом коде без доработок, проверьте актуальность релиза конфигурации: известные ошибки платформа и вендор исправляют в обновлениях. При повторяющихся сбоях в типовой поставке на актуальном релизе разумно зафиксировать стек вызовов и передать его в поддержку вендора.
Как выбрать действие
Частые вопросы
Почему ошибка возникает только на одном элементе справочника?
Скорее всего, в данных этого элемента есть циклическая ссылка: например, родитель указывает на собственного потомка, и рекурсивный обход иерархии уходит в бесконечный цикл. Проверьте цепочку родителей элемента и исправьте данные, а в код добавьте контроль уже посещённых узлов.
Поможет ли увеличение памяти сервера или перезапуск служб?
Нет. Переполнение стека — это ограничение на глубину вложенных вызовов внутри потока, а не нехватка оперативной памяти. Бесконечная рекурсия исчерпает стек любого размера, поэтому нужно исправлять код или данные, а не инфраструктуру.
Почему в тексте ошибки указана строка, где нет ничего подозрительного?
Указанная строка — место, где стек исчерпался в момент очередного вызова, а не источник проблемы. Истинную причину показывает стек вызовов в технологическом журнале: повторяющаяся цепочка процедур в нём и есть зацикленный участок.
Может ли переполнение стека возникнуть без рекурсии?
Да, через косвенную рекурсию: взаимные вызовы разных модулей, обработчики событий, инициирующие запись объектов, подписки на события, вызывающие друг друга. Внешне ни одна процедура не вызывает сама себя, но цепочка замыкается в кольцо.
Как защитить обработчик ПриЗаписи от зацикливания?
Используйте дополнительные свойства объекта: перед записью связанного объекта установите в его дополнительных свойствах собственный признак, а в начале обработчика проверяйте его наличие и пропускайте повторную обработку. Альтернатива — проверять, действительно ли изменились данные, прежде чем инициировать новую запись.
Опасна ли эта ошибка для данных базы?
Сама по себе ошибка прерывает выполнение кода и транзакция откатывается, поэтому прямой порчи данных обычно нет. Риск возникает при попытках исправления: правка кода или данных в рабочей базе без копии может повредить учётные данные, поэтому все изменения выполняйте сначала на копии.
Что важно запомнить
Переполнение стека встроенного языка на сервере 1С — следствие бесконечной или слишком глубокой цепочки вызовов, чаще всего рекурсии без выхода или зацикливания обработчиков событий. Диагностируйте по стеку вызовов в технологическом журнале, ищите повторяющуюся цепочку, добавляйте условия выхода и защиту от циклических данных, а исправления проверяйте на копии базы.