Стек вызовов¶
Стек вызовов отвечает на один вопрос: как исполнение сюда попало?
Открывается по Ctrl+C. Каждая строка — фрейм, то есть выполняющаяся сейчас функция; самая внутренняя сверху. Нижняя строка — место, где начался поток.
Выбор фрейма¶
В этой панели курсор и выделение — одно и то же: движение по J / K или стрелкам сразу выбирает фрейм, нажимать Enter не нужно. За выбором следуют остальные панели:
- Переменные показывают области видимости этого фрейма;
- Evaluate вычисляет выражения в нём;
- Watches пересчитываются относительно него;
- панель исходника показывает строку этого фрейма.
Выбор фрейма не двигает исполнение. Вы смотрите в прошлое текущей остановки, а не отматываете к нему.
Как читать стек¶
Идите сверху вниз. Первый фрейм, код которого принадлежит вам, обычно и есть место проблемы: всё, что выше, — библиотечный код или рантайм, делающие ровно то, о чём их попросили.
Если почти весь стек состоит из незнакомых фреймов, значит сбой вызван изнутри фреймворка — найдите первый фрейм из своего проекта и посмотрите его переменные.
Фреймы без исходника¶
Фрейм может указывать на код, который отладчику нечем показать: стандартная библиотека, собранная без отладочной информации; зависимость, исходников которой нет на этой машине; код в контейнере по пути, которого локально не существует.
Фрейм при этом остаётся в списке, его можно выбрать, и переменные могут быть доступны, даже когда исходника нет. А вот если исходника нет у фреймов, которые принадлежат вам, значит пути расходятся, и лечится это отображениями путей: Диагностика → Исходник не найден.
Глубокие стеки¶
Рекурсивные программы дают очень длинные стеки. G прыгает в начало, Shift+G — в конец; обычно это быстрее, чем прокруткой искать границу между своим кодом и рантаймом.