Перейти к содержанию

Стек вызовов

Стек вызовов отвечает на один вопрос: как исполнение сюда попало?

Открывается по Ctrl+C. Каждая строка — фрейм, то есть выполняющаяся сейчас функция; самая внутренняя сверху. Нижняя строка — место, где начался поток.

Выбор фрейма

В этой панели курсор и выделение — одно и то же: движение по J / K или стрелкам сразу выбирает фрейм, нажимать Enter не нужно. За выбором следуют остальные панели:

  • Переменные показывают области видимости этого фрейма;
  • Evaluate вычисляет выражения в нём;
  • Watches пересчитываются относительно него;
  • панель исходника показывает строку этого фрейма.

Выбор фрейма не двигает исполнение. Вы смотрите в прошлое текущей остановки, а не отматываете к нему.

Как читать стек

Идите сверху вниз. Первый фрейм, код которого принадлежит вам, обычно и есть место проблемы: всё, что выше, — библиотечный код или рантайм, делающие ровно то, о чём их попросили.

Если почти весь стек состоит из незнакомых фреймов, значит сбой вызван изнутри фреймворка — найдите первый фрейм из своего проекта и посмотрите его переменные.

Фреймы без исходника

Фрейм может указывать на код, который отладчику нечем показать: стандартная библиотека, собранная без отладочной информации; зависимость, исходников которой нет на этой машине; код в контейнере по пути, которого локально не существует.

Фрейм при этом остаётся в списке, его можно выбрать, и переменные могут быть доступны, даже когда исходника нет. А вот если исходника нет у фреймов, которые принадлежат вам, значит пути расходятся, и лечится это отображениями путей: Диагностика → Исходник не найден.

Глубокие стеки

Рекурсивные программы дают очень длинные стеки. G прыгает в начало, Shift+G — в конец; обычно это быстрее, чем прокруткой искать границу между своим кодом и рантаймом.