StackOverflow во время инициализации
✅ Паттерн воспроизведён в Political World 💥 Troubleshooting
StackOverflow во время запуска, инициализации мира, создания государства или другого первого setup часто означает, что небольшая группа методов косвенно вызывает сама себя.
Типичная форма
Заголовок раздела «Типичная форма»A() ↓B() ↓C() ↓A() ↓B() ↓C() ...В исходнике вовсе не обязательно будет очевидный вызов вида A() { A(); }.
В реальном моде гораздо чаще встречается косвенная рекурсия.
Частые причины
Заголовок раздела «Частые причины»Getter инициализирует отсутствующее состояние
Заголовок раздела «Getter инициализирует отсутствующее состояние»Thing GetThing(){ if (thing == null) SetThing(CreateThing());
return thing;}Если SetThing() в итоге снова вызывает GetThing(), цикл готов.
Setter вызывает callback
Заголовок раздела «Setter вызывает callback»SetState() → event/callback → listener читает State → getter пытается инициализировать → SetState()Повторный вход через Harmony
Заголовок раздела «Повторный вход через Harmony»Prefix/Postfix может вызвать метод, который в итоге снова приводит к пропатченному методу.
Исправление не всегда заключается в «убрать Harmony». Сначала нужно доказать, где именно замыкается цикл.
Как отлаживать
Заголовок раздела «Как отлаживать»- Найдите самый маленький повторяющийся набор методов в stack/log.
- Нарисуйте между ними стрелки.
- Отметьте, какие функции читают состояние, а какие его меняют.
- Ищите read-функцию, которая скрытно мутирует или инициализирует объект.
- Сделайте отдельную одноразовую функцию инициализации с guard.
- Пусть getter возвращает данные, а не пытается автоматически починить весь граф объектов.
- Повторно протестируйте именно тот сценарий первой инициализации, который падал.
Пример guard
Заголовок раздела «Пример guard»Guard может защитить от случайного повторного входа:
private bool _initializing;
void EnsureInitialized(){ if (_initialized || _initializing) return;
_initializing = true; try { // инициализация без getter, способных снова войти сюда _initialized = true; } finally { _initializing = false; }}Guard не заменяет понимание причины. Это дополнительная защита после того, как зависимости инициализации приведены в нормальный вид.
Реальный случай
Заголовок раздела «Реальный случай»Political World воспроизвёл этот паттерн, когда у нового государства отсутствовали данные формы правления.
См.: Political World — рекурсия при инициализации правительства.