Finding SWT Leaks with Sleak
In SWT, the mantra is “if you created it, you dispose it.”
The problem is, people forget to dispose which makes leaks a reality.
For example, ever come across this dreaded exception from SWT? java ... org.eclipse.swt.SWTError: No more handles at org.eclipse.swt.SWT.error(SWT.java:2966) at org.eclipse.swt.SWT.error(SWT.java:2863) at org.eclipse.swt.SWT.error(SWT.java:2834) at org.eclipse.swt.widgets.Widget.error(Widget.java:395) at org.eclipse.swt.widgets.Control.createHandle(Control.java:482) at org.eclipse.swt.widgets.Composite.createHandle(Composite.java:229) at org.eclipse.swt.widgets.Control.createWidget(Control.java:497) at org.eclipse.swt.widgets.Scrollable.createWidget(Scrollable.java:131) at org.eclipse.swt.widgets.Control. (Control.java:97) at org.eclipse.swt.widgets.Scrollable. (Scrollable.java:72) at org.eclipse.swt.widgets.Composite. (Composite.java:87) ...
One of the most common causes of this type of exception is a resource leak. In SWT, you’re allocating operating system resources for widgets, images, fonts, and other graphical objects. Since there is a platform-specific limit on the amount of resources you can allocate, you must be careful to free any objects that you allocate. To see what resources your application has allocated, the SWT team has a tool called Sleak. To get an idea of how Sleak works, let’s modify the famous RCP Mail example. The first step will be to add the Sleak view to the RCP Mail perspective (Perspective.java): java layout.addStandaloneView(NavigationView.ID, false, IPageLayout.LEFT, 0.25f, editorArea); IFolderLayout folder = layout.createFolder("messages", IPageLayout.TOP, 0.5f, editorArea); folder.addPlaceholder(View.ID + ":\*"); folder.addView(View.ID); folder.addView("org.eclipse.swt.sleak.views.SleakView"); // add sleak here!
The next step is to simulate a leak so we can show the benefit of using Sleak. We can simulate a resource leak by creating a bold font and never disposing of it in the RCP Mail view (View.java): java ... // setup bold font // comment out the safe way of getting a bold font via the jface registry // Font boldFont = JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT\_FONT); FontData\[\] fontData = JFaceResources.getDialogFont().getFontData(); for (int i = 0; i < fontData.length; i++) { FontData data = fontData\[i\]; data.setStyle(SWT.BOLD); } boldFont = new Font(parent.getDisplay(), fontData); // this should be disposed in dispose() ...
Ok, now that we have the code modifications out of the way, we need to launch our application. Note, in order to have Sleak function properly, you have to enable some options: org.eclipse.ui/debug=true org.eclipse.ui/trace/graphics=true
The easiest way to do this is in your Eclipse application launch configuration. There is a ‘Tracing’ tab that allows you to tweak options:
Once that is done, we can launch our application and find the ‘Sleak’ view:
If you press the ‘Snap’ button in Sleak, it will take a snapshot of the current allocated resources. To demonstrate the leak, we need to open two more messages in the mail application, close both of them, and then go back to the Sleak view to press the ‘Diff’ button:
Sleak now informs us that there are two more fonts allocated than before, we have found our leak! If you click the ‘Stack’ option, you can even get a stracktrace that tells you where the resource was allocated. A fix for this problem goes back to the SWT mantra of “if you created it, you dispose it.” In our view, we simply need to dispose of the bold font when we’re done using it (or use the font registry like before): java ... public void dispose() { super.dispose(); boldFont.dispose(); // we need to dispose that font to prevent a leak! } ...
Here’s a zip of mail example with the leak if you want to toy with Sleak.
Hope this helps!