Подтвердить что ты не робот

Почему условная отладка настолько медленная?

Я заметил, что при отладке с условными точками останова выполнение значительно замедляется. Я знаю это некоторое время и теперь хотел бы понять, почему. Что именно происходит, что приводит к тому, что выполнение происходит так медленно? Я знаю, что добавляется условие, но если я сам добавлю условие, я не замедляю выполнение.

Например, скажем, у нас есть следующий код. И предположим, что мы добавляем условную точку останова a=i. Позволяет просто установить условие для я == 10000.

public class Main {

    public static void main(String[] args) {
        int a = 0;

        for (int i = 0; i<100000; i++) {
                a = i;  //put breakpoint here (if i == 10000)
        }
        System.out.println("Done! a=" + a);
    }
}

Теперь вместо этого напишем условное выражение.

public class Main {

    public static void main(String[] args) {
        int a = 0;

        for (int i = 0; i<100000; i++) {
            if (i == 10000)
                a = i; //put a NON-conditional breakpoint here
            else a = i;
        }
        System.out.println("Done! a=" + a);
    }
}

Почему время запуска обоих из них настолько резко отличается? Почему первый так медленнее?

В случае вашего удивления, я использую Oracle-JDK-8 для Linux (Ubuntu). Я получаю те же результаты с Eclipse и IntelliJ.


Результаты эксперимента

Я проверил первый случай на нескольких IDE, чтобы узнать, есть ли разница. Вот результаты

IntelliJ:

~ 9 секунд, чтобы попасть в точку останова

~ 90 секунд, чтобы завершить выполнение (включая начальные 9 секунд)

Eclipse:

~ 9 секунд, чтобы попасть в точку останова

~ 90 секунд, чтобы завершить выполнение (включая начальные 9 секунд)

Netbeans:

~ 12 секунд, чтобы попасть в точку останова

~ 190 секунд, чтобы завершить выполнение (включая начальные 12 секунд)

Итак, IntelliJ и Eclipse примерно одинаковы, но Netbeans намного медленнее.

Второй пример выполняется почти мгновенно на всех IDE, поэтому я не экспериментировал. (Но я запустил все три, чтобы увидеть, есть ли у кого-нибудь из них задержка, никто из них не сделал.)

4b9b3361

Ответ 1

Я не реализовал IDE, отладчик или JVM, поэтому я не могу быть уверен, что все происходит точно так, как я объясню здесь.

Но. Когда код работает с отладчиком, JVM интерпретирует код, пока он не встретит точку останова. Затем он останавливается и вызывает отладчик (IDE).

JVM не поддерживают условные точки останова, поэтому среда IDE использует "хак" для выполнения этой функции. IDE просто добавляет нормальную точку останова. Каждый раз, когда ударяется точка останова, среда IDE оценивает само выражение перед предупреждением пользователя, если оценка ложна, он отправляет команду "продолжить".

Теперь рассмотрите ваши примеры. Во втором примере JVM выполняет такой вызов только один раз. В первом примере это делается 100000 раз. Каждый раз, когда JVM вызывает отладчик и ждет, пока он не интерпретирует условие, и отправляет команду JVM "продолжить" (точно так же, как вы можете сделать вручную, когда вы отлаживаете свой код). Очевидно, 100000 > 1, поэтому этот процесс требует времени.

EDIT: следующие 2 абзаца были написаны как недоказанное предположение. Эксперименты ОП показали, что они ошибаются. Однако я не хочу их полностью удалить: интерпретировать это как предложение о теоретическом мышлении и улучшении для команды Eclipse.

Относительно IntelliJ против Eclipse. Опять же, это предположение. Я видел, что IntelliJ работает намного медленнее с условными точками останова. Я также знаю, что условные точки останова в IntelliJ не поддерживают некоторые элементы языка Java-программирования (например, анонимные внутренние классы). Я могу заключить, что IntelliJ, вероятно, компилирует код, который вы пишете как условие вашего brekepoint, используя язык, отличный от java (например, groovy или что-то еще). Это, вероятно, вызывает дополнительную деградацию производительности.

Я также знаю, что eclipse не использует стандартный компилятор javac, а свой собственный компилятор с множеством интересных функций. Я могу предположить, что, вероятно, условные точки останова в eclipase скомпилированы как часть вашего кода, то есть на самом деле компилятор автоматически создает код, например, ваш номер примера 2. Если это так, то такой код будет работать почти так же быстро, как код, содержащий вручную написанный if утверждение.

Ответ 2

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

Быстрое достижение точки останова: последовательный поток выполнения прерывается, например, заменяя инструкцию в этом месте некоторым кодом, который запускает прерывание. Но оценка условия должна извлекать значения переменных из памяти и вычислять результат, который не делается таким же образом, как выражение будет оценивать в скомпилированном коде. Ожидается значительное замедление.

В то время как скомпилированное выражение приводит к машинным инструкциям (в Java, по крайней мере, после компиляции JIT), интерпретируемое выражение основано на абстрактном синтаксическом дереве (структуре данных), таком как Equals( Variable( "i" ), Literal( 10000 )) и код, который спускается по этим данным структуры, выбирает значения ( "i" ) и вычисляет операции ( "==" ).