Time for action – plugging the leak
Now that the leak has been discovered, it needs to be fixed. The solution is to call dispose
on the Color
once the view itself is removed.
A quick investigation of the ClockWidget
suggests that overriding dispose
might work, though this is not the correct solution; see later for why.
- Create a dispose method in
ClockWidget
with the following code:@Override public void dispose() { if (color != null && !color.isDisposed()) color.dispose(); super.dispose(); }
- Run the target Eclipse application in debug mode (with the tracing enabled, as before) and open and close the view. The output will show something like this:
There are 87 Color instances There are 91 Color instances There are 94 Color instances There are 98 Color instances
- Remove the
dispose
method (since it doesn't work as intended) and modify the constructor of theClockWidget
to add an anonymousDisposeListener
that disposes of the associatedColor
:public ClockWidget(Composite parent, int style, RGB rgb) { super(parent, style); this.color = new Color(parent.getDisplay(), rgb); addDisposeListener(e -> color.dispose()); }
- Now run the code and see what happens when the view is opened and closed a few times:
There are 87 Color instances There are 88 Color instances There are 88 Color instances There are 88 Color instances
- The leak has been plugged.
What just happened?
Once the source of the leak has been identified, the correct course of action is to dispose
the Color
when no longer needed. However, although it is tempting to think that overriding the dispose
method of the ClockWidget
would be all that is needed, it doesn't work. The only time dispose
is called is at the top level Shell
(or View
), and if there are no registered listeners, then the dispose
method is not called on any components beneath. Since this can be quite counter-intuitive, it is of value to step through the code to verify that that is the behavior so that it can be avoided in the future.
Detecting and resolving resource leaks can be a time-consuming process. There are SWT Tools plug-ins developed by the SWT team that can perform a snapshot of resources and check whether there are any leaks using a similar technique. The plug-ins are located at the SWT tools update site (which are listed at http://www.eclipse.org/swt/updatesite.php) and can be installed to avoid having to modify code (for the purpose of monitoring allocated resources).
Don't forget when performing tests that the first one or two runs may give different results by virtue of the fact that other resources may be getting initialized at the time. Take a couple of readings first before relying on any data, and bear in mind that other plug-ins (which may be executing in the background) could be doing resource allocation at the same time.
Finally, when working with any SWT widget, it is good practice to check whether the resource is already disposed. The JavaDoc for the dispose
method says that this is not strictly necessary, and that resources that are already disposed will treat this as a no-op method.
Pop quiz – understanding resources
Q1. Where do resource leaks come from?
Q2. What are the different types of Resource
classes?
Q3. How can you enable SWT resource tracking?
Q4. Once enabled, how do you find out what objects are tracked?
Q5. What's the right way, and wrong way, to free resources after use?
Have a go hero
Now that the ClockWidget
is running, try the following:
- Write a Sleak-like view that periodically counts allocated objects by type
- Modify any text written by acquiring a
Font
object, with disposal - Create a generic dispose listener that takes an instance of
Resource
- Provide a
setColor
method that allows you to change the color