Emilian has posted 6 posts at DZone. View Full User Profile

Using VisualVM, BTrace & Good Old Web Search

08.20.2009
| 27631 views |
  • submit to reddit
Next, I compiled the script using btracec Script.java, then I executed it with btrace $PID Script.class where $PID is the actual numeric process ID (for example 2377). The execution prints a lot of debugging info and I found out that I have some instances that look like this:

org.netbeans.modules.progress.ui.NbProgressBar@48aa00ec

What I care about now is detecting where those instances are created. Of course, I'll need to restart the application to detect when that happens and start the agent as soon as possible.

NOTE: I did this step manually by having the commands ready in the terminal, but presumably you could attach a btrace agent from the start to the IDE and run that script. This didn't work for me and I didn't bother checking it out.

Finding the stacktrace for the constructor is just a matter of another script method and BTraceUtils.jstack():

@OnMethod(clazz="org.netbeans.modules.progress.ui.NbProgressBar",
method="<init>")
public static void instantiate(@Self Object o ){
println(strcat("Instantiated org.netbeans.modules.progress.ui.NbProgressBar: ",str(o)));
jstack();
println("----");
}

And this is where we strike gold! The two common stacktraces are:

org.netbeans.modules.progress.ui.StatusLineComponent.createBar(StatusLineComponent.java:170)
org.netbeans.modules.progress.ui.StatusLineComponent.initiateComponent(StatusLineComponent.java:377)
org.netbeans.modules.progress.ui.StatusLineComponent.processSelectedProgressEvent(StatusLineComponent.java:329)
org.netbeans.progress.module.Controller.run(Controller.java:337)
java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:300)
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:210)
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:200)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:195)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:187)
java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

and

org.netbeans.modules.progress.ui.ListComponent.<init>(ListComponent.java:105)
org.netbeans.modules.progress.ui.StatusLineComponent.createListItem(StatusLineComponent.java:439)
org.netbeans.modules.progress.ui.StatusLineComponent.processProgressEvent(StatusLineComponent.java:290)
org.netbeans.progress.module.Controller.run(Controller.java:339)
java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:300)
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:210)
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:200)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:195)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:187)
java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

In other words, our 'leaky' instances are here:

org.netbeans.modules.progress.ui.StatusLineComponent.createBar

org.netbeans.modules.progress.ui.ListComponent

What I still hadn't figured out is what's causing the animator to continue being called. This is where I resorted to good old Google search and typed "apple.laf.CUIAquaProgressBar$Animator". It's a very uncommon request since I just got 7 items, and the 4th one was an IDEA bugreport. They were complaining about the same thing! And one of the posters there found a workaround... just uninstall the UI.

progress.getUI().uninstallUI(progress) seems to be the magic line.

With this new knowledge, I looked into the two targeted classes, to find out where the ProgressBar is released. Sure enough, one of them has a discardBar method, while the other will need an additional method. I patch the methods, change the btrace script to double-check those methods too, and rebuild NetBeans IDE.

NOTE: This is the only downside until now. While investigating this was done directly on the IDE binaries, patching it required the source code.

That was it. Running the btrace script with the patched classes showed that the OSX animator class isn't called anymore! While this wasn't a bug per-se in the IDE, more like an OSX JDK issue, the workaround did reduce my CPU usage!

After cleaning up the patch, I'm ready to submit it to NetBeans for inclusion. In a surprisingly fast fashion, my bug report was accepted and included in about 1 hour 30 minutes. I guess marking it as a P2 priority sped things up a little.

If you found this article interesting and appreciate your better battery this patch brought into your life, feel free to send your spare battery my way... it will be put to good (ab)use.

Published at DZone with permission of its author, Emilian Bold.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Philippe Lhoste replied on Fri, 2009/08/21 - 4:25am

Beyond the particular context not interesting everyone (I don't use OSX nor NetBeans...), I appreciated the report of the detective work you did, showing good usage of tools. I knew VisualVM but it is the first time I see how to use BTrace, which is indeed an interesting tool if you can't (or don't want to) alter source code to add println's...

Thanks for sharing!

Mateo Gomez replied on Tue, 2012/04/17 - 12:20am

thanks for sharing this valuable information to us, i know you have put in a lot of hard work in this project

 

 mexican dessert recipes

Matt Coleman replied on Tue, 2012/04/17 - 12:46am

debugging is such an important thing to do to fix the program and make it work

 

graphic design buffalo

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.