IntelliJ Уловки отладки

IntelliJ Уловки отладки

1. обзор

В этом руководстве мы рассмотрим несколькоadvanced IntelliJ debugging facilities.

Предполагается, что основы отладки уже известны (как начать отладку, действияStep Into,Step Over и т. Д.). Если нет, обратитесь кthis article для получения более подробной информации.

2. Умный шаг внутрь

Бывают ситуации, когда в одной строке исходного кода вызывается несколько методов, напримерdoJob(getArg1(), getArg2()). Если мы вызываем действиеStep Into (F7), отладчик переходит к методам в порядке, используемом JVM для оценки:getArg1 -getArg2 -doJob.

Однакоwe might want to skip all intermediate invocations and proceed to the target method directly. ДействиеSmart Step Into позволяет это сделать.

Этоbound to the Shift + F7 by default и при вызове выглядит так:

image

Теперь мы можем выбрать целевой метод для продолжения. Также обратите внимание, что IntelliJ всегда помещает самый дальний метод в начало списка. Это означает, что мы можем быстро перейти к нему, нажавShift + F7 | Enter.

3. Drop Frame

Мы можем понять, что некоторая обработка, которая нас интересует, уже произошла (например, вычисление аргумента текущего метода). В этом случаеit’s possible to drop the current JVM stack frame(s) in order to re-process them.

Рассмотрим следующую ситуацию:

image

Предположим, нас интересует отладка обработкиgetArg1, поэтому мы отбрасываем текущий кадр (методdoJob):

image

Теперьwe’re in the previous method:

image

Однако аргументы вызова уже вычислены на этом этапе, поэтомуwe need to drop the current frame as well:

image

Теперь мы можем повторно запустить обработку, вызвавStep Into.

4. Полевые точки останова

Иногда неприкосновенные поля изменяются другими классами, но не через сеттеры, а напрямую (как в случае со сторонними библиотеками, исходный код которых мы не контролируем).

В таких ситуациях может быть трудно понять, когда модификация сделана. IntelliJ позволяет создавать точки останова на уровне поля, чтобы отслеживать это.

Они установлены как обычно - щелкните левой кнопкой мыши на левом желобе редактора на линии поля. После этого можноopen breakpoint properties (right-click on the breakpoint mark) and configure if we’re interested in the field’s reads, writes, or both:

image

5. Регистрация точек останова

Иногда мы знаем, что в приложении есть состояние гонки, но не знаем, где именно. Это может быть проблемой, особенно при работе с новым кодом.

Мы можем добавлять операторы отладки в исходный код нашей программы. Однако для сторонних библиотек такой возможности нет.

Здесь может помочь IDE -it allows setting breakpoints that don’t block execution once hit, but produce logging statements instead.

Рассмотрим следующий пример:

public static void main(String[] args) {
    ThreadLocalRandom random = ThreadLocalRandom.current();
    int count = 0;
    for (int i = 0; i < 5; i++) {
        if (isInterested(random.nextInt(10))) {
            count++;
        }
    }
    System.out.printf("Found %d interested values%n", count);
}

private static boolean isInterested(int i) {
    return i % 2 == 0;
}

Предположим, нас интересует регистрация фактических параметров вызоваisInterested.

Давайте создадим неблокирующую точку останова в целевом методе (Shift + щелчок левой кнопкой мыши по левому краю поля редактора). После этого откроем его свойства (щелкните правой кнопкой мыши точку останова) иdefine the target expression to log:

image

При запуске приложения (обратите внимание, что по-прежнему необходимо использовать режим отладки) мы увидим результат:

isInterested(1)
isInterested(4)
isInterested(3)
isInterested(1)
isInterested(6)
Found 2 interested values

6. Условные точки останова

У нас может возникнуть ситуация, когда определенный метод вызывается из нескольких потоков одновременно, и нам нужно отладить обработку только для определенного аргумента.

IntelliJ допускаетcreating breakpoints that pause the execution only if a user-defined condition is satisfied.

Вот пример, в котором используется приведенный выше исходный код:

imageimage

Теперь отладчик остановится на точке останова, только если заданный аргумент больше 3.

7. Метки объекта

Это самая мощная и наименее известная функция IntelliJ. По сути это довольно просто -we can attach custom labels to JVM objects.

Давайте посмотрим на приложение, которое мы будем использовать для их демонстрации:

public class Test {

    public static void main(String[] args) {
        Collection tasks = Arrays.asList(new Task(), new Task());
        tasks.forEach(task -> new Thread(task).start());
    }

    private static void mayBeAdd(Collection holder) {
        int i = ThreadLocalRandom.current().nextInt(10);
        if (i % 3 == 0) {
            holder.add(i);
        }
    }

    private static class Task implements Runnable {

        private final Collection holder = new ArrayList<>();

        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                mayBeAdd(holder);
            }
        }
    }
}

7.1. Создание знаков

Объект может быть отмечен, когда приложение остановлено на точке останова и цель достижима из кадров стека.

Выберите его, нажмитеF11 (действиеMark Object) и укажите имя цели:

image

7.2. Посмотреть отметки

Теперь мы можем видеть наши собственные ярлыки объектов даже в других частях приложения:

imageimage

Приятно то, чтоeven if a marked object is not reachable from stack frames at the moment, we can still see its state - откройте диалоговое окноEvaluate Expression или добавьте новые часы и начните вводить имя отметки.

IntelliJ предлагает дополнить его суффиксом_DebugLabel:

imageimage

Когда мы его оцениваем, отображается состояние целевого объекта:

imageimage

7.3. Знаки как условия

Также можно использовать метки в условиях точки останова:

imageimage

8. Заключение

Мы проверили ряд методов, которые значительно повышают производительность при отладке многопоточного приложения.

Обычно это сложная задача, и мы не можем недооценивать важность помощи инструментария.