Question About Eclipse Java Debugger Conditional Breakpoints Inefficiency
I just set a conditional breakpoint in Eclipse's debugger with a mildly inefficient condition by breakpoint standards - checking whether a HashMap's value list (8 elements) contains Double.NaN. This resulted in an extremely noticeable slowdown in performance - after about five minutes, I gave up.
Then I copy pasted the condition into an if statement at开发者_StackOverflow中文版 the exact same line, put a noop in the if, and set a normal breakpoint there. That breakpoint was reached in the expected 20-30 seconds.
Is there something special that conditional breakpoints do that makes the performance hit worthwhile, or is Eclipse's implementation just kinda stupid? It seems like they could fairly easily just do exactly the same thing (paste in an if and compile) behind the scenes.
Interesting!
I played with some source code to see what is happening with and without a conditional breakpoint. Attached below.
Execution in the debugger with the conditional breakpoint:
Duration: 1210623 microseconds
Execution in the debugger without the conditional breakpoint:
Duration: 24 microseconds
IMHO the VM is not stopped because the second thread continues to run side-by-side. Eclipse does have to inject the breakpoint code into the current class. Maybe it does so on every call and maybe it has to recompile the class on every call. Checking the Eclipse sources would reveal what is happening exactly.
My experience running conditional breakpoints in C# and in Visual Studio is even worse: My stomach feeling is that things are a couple of orders of magnitude worse there.
public class BreakPointPlay {
static int breakpointHits;
static volatile int modifiedBySecondThread;
static volatile boolean stopped;
public static void main(String[] args) throws InterruptedException {
Thread secondThread = startSecondThread();
final long LOOPS = 1000;
long counter = 0;
long start = System.nanoTime();
for (long i = 0; i < LOOPS; i++) {
// place breakpoint here and set the condition to the
// #breakPointCondition() method.
counter += i;
}
long stop = System.nanoTime();
long nanos = stop - start;
long micros = nanos / 1000;
System.out.println("\nDuration: " + micros + " microseconds\n");
printInfo();
stopped = true;
secondThread.join();
}
private static Thread startSecondThread() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while(! stopped){
modifiedBySecondThread++;
}
}
});
thread.start();
return thread;
}
private static void printInfo() {
printModifiedBySecondThread();
printThread();
printClassLoader();
printStackTrace();
printModifiedBySecondThread();
}
private static void printStackTrace() {
Exception exception = new Exception();
exception.fillInStackTrace();
exception.printStackTrace(System.out);
}
private static void printModifiedBySecondThread() {
print("modifiedBySecondThread " + modifiedBySecondThread);
}
public static boolean breakPointCondition(){
breakpointHits++;
if(breakpointHits == 100){
printInfo();
}
return false;
}
private static void printClassLoader() {
print("ClassLoader " + new BreakPointPlay().getClass().getClassLoader());
}
private static void printThread() {
print("Thread " + Thread.currentThread());
}
private static void print(String msg){
System.out.println(msg);
}
}
How many times was the breakpoint passed? It may be that the debugger has had to test the breakpoint condition many times before it triggering. I do not know how it's implemented but I would not be surprised if the debugger's execution of the condition is a lot less efficient than normally compiled Java would be. Perhaps it's simply that it gets less attention from the JIT. Perhaps its not even fully compiled to Java at all and is interpreted.
Eclipse needs to stop the whole JVM in order to examine the breakpoint condition. This is why it is costing you.
精彩评论