Eclipse Plug-in Development:Beginner's Guide(Second Edition)
上QQ阅读APP看书,第一时间看更新

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.

  1. Create a dispose method in ClockWidget with the following code:
    @Override
    public void dispose() {
      if (color != null && !color.isDisposed())
        color.dispose();
      super.dispose();
    }
  2. 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
  3. Remove the dispose method (since it doesn't work as intended) and modify the constructor of the ClockWidget to add an anonymous DisposeListener that disposes of the associated Color:
    public ClockWidget(Composite parent, int style, RGB rgb) {
      super(parent, style);
      this.color = new Color(parent.getDisplay(), rgb);
      addDisposeListener(e -> color.dispose());
    }
  4. 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
  5. 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