I have noticed that when I debug with conditional breakpoints, execution is dramatically slowed down. I have known this for a while, and would now like to understand why. What exactly is happening that causes execution to be so slow? I know that a conditional is being added, but if I add the conditional myself, I don't slow down execution.
For example, lets say we have the following code. And lets say we add a conditional breakpoint a=i
. Lets just set the conditional to 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); } }
Now lets instead, write the conditional ourselves.
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); } }
Why is the run time of both of these so dramatically different? Why is the first one so much slower?
In case your wondering, I am using Oracle-JDK-8 on Linux (Ubuntu). I get the same results with Eclipse and IntelliJ.
I ran the first case on multiple IDE's to see if there is a difference. Here are the results
IntelliJ:
~9 seconds to hit breakpoint
~90 seconds to hit completion (including initial 9 seconds)
Eclipse:
~9 seconds to hit breakpoint
~90 seconds to hit completion (including initial 9 seconds)
Netbeans:
~ 12 seconds to hit breakpoint
~ 190 seconds to hit completion (including initial 12 seconds)
So IntelliJ and Eclipse are about the same, but Netbeans is much much slower.
The second example runs almost instantaneously on all IDE's, so I did not do an experiment. (But I did run it all all three to see if any of them had a delay, none of them did.)
Method breakpoints will slow down debugger a lot because of the JVM design, they are expensive to evaluate. Remove method breakpoints and consider using the regular line breakpoints. To verify that you don't have any method breakpoints open .
Conditional breakpoints allow you to break inside a code block when a defined expression evaluates to true. Conditional breakpoints highlight as orange instead of blue. Add a conditional breakpoint by right clicking a line number, selecting Add Conditional Breakpoint , and entering an expression.
To set a conditional breakpoint, activate the context menu in the source pane, on the line where you want the breakpoint, and select “Add Conditional Breakpoint”. You'll then see a textbox where you can enter the expression. Press Return to finish.
I have not implemented IDE, debugger or JVM, so I can not be sure that the things are going exactly as I will explain here.
But. When code is running with debugger the JVM interprets the code until it meets breakpoint. Then it stops and calls debugger (IDE).
JVM's do not support conditional breakpoints, so IDE's use a "hack" to accomplish this feature. The IDE simply adds a normal breakpoint. Every time a breakpoint is hit, the IDE evaluates the expression itself before alerting the user, if the evaluation is false, it sends the "continue" command.
Now examine your examples. In second example JVM performs such call only once. In first example this is done 100000 times. Each time JVM calls debugger and waits until it interprets the condition and sends to JVM command "continue" (exactly as you can do manually when you are debugging your code). Obviously 100000>1, so this process takes time.
EDIT: the next 2 paragraphs were written as an not proven assumption only. The experiments of OP showed that they are wrong. I however do not want to remove them completely: let's interpret this as a theoretical thinking and improvement proposal for Eclipse team.
Concerning IntelliJ vs Eclipse. Again, this is assumption only. I saw that IntelliJ works much slower with conditional breakpoints. I know also that conditional breakpoints in IntelliJ do not support some elements of java programming language (e.g. anonymous inner classes). I can conclude that IntelliJ probably compiles the code that you write as a condition of your brekepoint using language other than java (for example groovy or something). This probably causes additional performance degradation.
I also know that eclipse does not use standard javac compiler but its own compiler that has a lot of cool features. I can assume that probably conditional breakpoints in eclipase are compiled as a part of your code, i.e. actually compiler automatically creates code like your example number 2. If this is correct such code will run almost as quickly as code that contains manually written if
statement.
Conditional breakpoints rely on the interpretative (!) evaluation of the condition, to be done whenever the location of the breakpoint is hit.
Hitting a breakpoint is fast: the sequential flow of execution is interrupted, e.g., by replacing the instruction at that location by some code that triggers an interrupt. But the evaluation of the condition must fetch the values of the variables from memory and compute the result, which isn't done the same way the expression would evaluate in compiled code. A considerable slow-down is to be expected.
While a compiled expression results in machine instructions (in Java, at least after JIT compilation), an interpreted expression is based on an abstract syntax tree (a data structure), such as Equals( Variable( "i" ), Literal( 10000 ))
and code that descends on that data structure, fetches values ("i") and computes operations ("==").
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With