`

org.eclipse.swt.SWTError: No more handles 续

 
阅读更多
[url]SWT中org.eclipse.swt.SWTError: No more handles[/url] 一文中有介绍,但最近又遇到这个问题。

其实,在那篇文章中提到的用Map 模拟注册表 缓存的方法是很凑效的,之所以又出现这个异常是因为一时疏漏 在一个方法中new Image后没有及时dispose该image(由于该image在Graphics中调用属于临时image 没必要放到map中,正确的方法是用完后dispose),而该方法又被频繁调用,这就又导致了该异常。

虽然最后的解决方案很简单,就添加一行image.dispose就ok了,不过由于项目比较大,想快速定位到错误的位置并不容易。

所以,如何跟踪软件(这里针对Eclipse RCP程序进行说明)的handler消耗呢?

其实打开Windows的任务管理器,可以在“性能”子页下的 句柄总数找到句柄的描述信息,但是如果我们想要知道RCP程序中具体的handler消耗,这个显然是不够的。

用Sleak工具可以快速定位句柄的消耗情况,来快速查出被过度消耗的handler出现在何处:

Sleak工具主要就是 org.eclipse.swt.sleak.jar 这个jar包,可以在http://www.eclipse.org/swt/tools.php 下载到。

http://www.eclipse.org/articles/swt-design-2/sleak.htm 官网上sleak的介绍

该包就有两个有效类Sleak.java和SleakView.java

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import java.io.*;

/**
 * Instructions on how to use the Sleak tool.
 * 
 * A) If you have access to the place where the display is created (most standalone applications):
 * 
 * Modify the creation of the Display as follows:
 * 
 * DeviceData data = new DeviceData();
 * data.tracking = true;
 * Display display = new Display(data);
 * Sleak sleak = new Sleak();
 * sleak.open();
 * Shell shell = new Shell(display);
 * 
 * B) If you do not have access to the place where the display is created (Eclipse):
 * 
 * 1) This tool will be referenced from the Device class so it needs to be copied into the same project.  
 *     Copy the package org.eclipse.swt.internal.tools to a source folder in the org.eclipse.swt project.
 * 
 * 2) This tool relies on debug information collected by the Device class.  Modify the Device class to 
 *     turn DEBUG on:
 * 
 *    public static boolean DEBUG = true;
 * 
 * 3)  The Sleak tool must be launched from the constructor of the Device class.
 *      Add the following lines to the end of the Device constructor:
 * 
 *   if (this.getClass().getName().equals("org.eclipse.swt.widgets.Display")) {
 *    org.eclipse.swt.internal.tools.Sleak sleak = new org.eclipse.swt.internal.tools.Sleak();
 *    sleak.open();
 *   }
 * 
 * 4) Create a new swt.jar for the platform you wish to test.  This is done by running the build.xml script 
 *     in the appropriate windowing system fragment.  Select the ws/$ws/swt.jar target.
 * 
 * 5) Copy the new swt.jar to the appropriate location.  When using Sleak with Eclipse, this is
 *     eclipse/org.eclipse.swt.<ws>_<version>/ws/<ws>
 * 
 * 6) Launch your application and the Sleak GUI will be displayed.  Click on the Snap button to
 *     capture the current resource state.  Click on the Diff button to compare the current state to 
 *     the previous snapshot state.
 * 
 */
public class Sleak {
 Display display;
 Composite parent;
 List list;
 Canvas canvas;
 Button start, stop, check;
 Text text;
 Label label;
 
 Object [] oldObjects = new Object [0];
 Error [] oldErrors = new Error [0];
 Object [] objects = new Object [0];
 Error [] errors = new Error [0];


public void open () {
 Display display = Display.getCurrent ();
 Shell shell = new Shell (display);
 shell.setText ("S-Leak");
 open (shell);
}
public void open (Composite parent2) {
 Composite composite = new Composite(parent2, SWT.NONE);
 parent = composite;
 parent.addListener(SWT.Resize, new Listener() {
  public void handleEvent (Event e) {
   layout ();
  }
 });
 this.display = Display.getCurrent ();
 list = new List (parent, SWT.BORDER | SWT.V_SCROLL);
 list.addListener (SWT.Selection, new Listener () {
  public void handleEvent (Event event) {
   refreshObject ();
  }
 });
 text = new Text (parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
 canvas = new Canvas (parent, SWT.BORDER);
 canvas.addListener (SWT.Paint, new Listener () {
  public void handleEvent (Event event) {
   paintCanvas (event);
  }
 });
 check = new Button (parent, SWT.CHECK);
 check.setText ("Stack");
 check.addListener (SWT.Selection, new Listener () {
  public void handleEvent (Event e) {
   toggleStackTrace ();
  }
 });
 start = new Button (parent, SWT.PUSH);
 start.setText ("Snap");
 start.addListener (SWT.Selection, new Listener () {
  public void handleEvent (Event event) {
   refreshAll ();
  }
 });
 stop = new Button (parent, SWT.PUSH);
 stop.setText ("Diff");
 stop.addListener (SWT.Selection, new Listener () {
  public void handleEvent (Event event) {
   refreshDifference ();
  }
 });
 label = new Label (parent, SWT.BORDER);
 label.setText ("0 object(s)");
 parent.addListener (SWT.Resize, new Listener () {
  public void handleEvent (Event e) {
   layout ();
  }
 });
 check.setSelection (false);
 text.setVisible (false);
 Point size = parent.getSize ();
 parent.setSize (size.x / 2, size.y / 2);
 parent.setVisible (true);
}

void refreshLabel () {
 int colors = 0, cursors = 0, fonts = 0, gcs = 0, images = 0;
 int paths = 0, patterns = 0, regions = 0, textLayouts = 0, transforms= 0;
 for (int i=0; i<objects.length; i++) {
  Object object = objects [i];
  if (object instanceof Color) colors++;
  if (object instanceof Cursor) cursors++;
  if (object instanceof Font) fonts++;
  if (object instanceof GC) gcs++;
  if (object instanceof Image) images++;
  if (object instanceof Path) paths++;
  if (object instanceof Pattern) patterns++;
  if (object instanceof Region) regions++;
  if (object instanceof TextLayout) textLayouts++;
  if (object instanceof Transform) transforms++;
 }
 String string = "";
 if (colors != 0) string += colors + " Color(s)\n";
 if (cursors != 0) string += cursors + " Cursor(s)\n";
 if (fonts != 0) string += fonts + " Font(s)\n";
 if (gcs != 0) string += gcs + " GC(s)\n";
 if (images != 0) string += images + " Image(s)\n";
 if (paths != 0) string += paths + " Paths(s)\n";
 if (patterns != 0) string += patterns + " Pattern(s)\n";
 if (regions != 0) string += regions + " Region(s)\n";
 if (textLayouts != 0) string += textLayouts + " TextLayout(s)\n";
 if (transforms != 0) string += transforms + " Transform(s)\n";
 if (string.length () != 0) {
  string = string.substring (0, string.length () - 1);
 }
 label.setText (string);
}

void refreshDifference () {
 DeviceData info = display.getDeviceData ();
 if (!info.tracking) {
  MessageBox dialog = new MessageBox (parent.getShell(), SWT.ICON_WARNING | SWT.OK);
  dialog.setText (parent.getShell().getText ());
  dialog.setMessage ("Warning: Device is not tracking resource allocation");
  dialog.open ();
 }
 Object [] newObjects = info.objects;
 Error [] newErrors = info.errors;
 Object [] diffObjects = new Object [newObjects.length];
 Error [] diffErrors = new Error [newErrors.length];
 int count = 0;
 for (int i=0; i<newObjects.length; i++) {
  int index = 0;
  while (index < oldObjects.length) {
   if (newObjects [i] == oldObjects [index]) break;
   index++;
  }
  if (index == oldObjects.length) {
   diffObjects [count] = newObjects [i];
   diffErrors [count] = newErrors [i];
   count++;
  }
 }
 objects = new Object [count];
 errors = new Error [count];
 System.arraycopy (diffObjects, 0, objects, 0, count);
 System.arraycopy (diffErrors, 0, errors, 0, count);
 list.removeAll ();
 text.setText ("");
 canvas.redraw ();
 for (int i=0; i<objects.length; i++) {
  list.add (objects [i].toString());
 }
 refreshLabel ();
 layout ();
}

void toggleStackTrace () {
 refreshObject ();
 layout ();
}

void paintCanvas (Event event) {
 canvas.setCursor (null);
 int index = list.getSelectionIndex ();
 if (index == -1) return;
 GC gc = event.gc;
 Object object = objects [index];
 if (object instanceof Color) {
  if (((Color)object).isDisposed ()) return;
  gc.setBackground ((Color) object);
  gc.fillRectangle (canvas.getClientArea());
  return;
 }
 if (object instanceof Cursor) {
  if (((Cursor)object).isDisposed ()) return;
  canvas.setCursor ((Cursor) object);
  return;
 }
 if (object instanceof Font) {
  if (((Font)object).isDisposed ()) return;
  gc.setFont ((Font) object);
  FontData [] array = gc.getFont ().getFontData ();
  String string = "";
  String lf = text.getLineDelimiter ();
  for (int i=0; i<array.length; i++) {
   FontData data = array [i];
   String style = "NORMAL";
   int bits = data.getStyle ();
   if (bits != 0) {
    if ((bits & SWT.BOLD) != 0) style = "BOLD ";
    if ((bits & SWT.ITALIC) != 0) style += "ITALIC";
   }
   string += data.getName () + " " + data.getHeight () + " " + style + lf;
  }
  gc.drawString (string, 0, 0);
  return;
 }
 //NOTHING TO DRAW FOR GC
// if (object instanceof GC) {
//  return;
// }
 if (object instanceof Image) {
  if (((Image)object).isDisposed ()) return;
  gc.drawImage ((Image) object, 0, 0);
  return;
 }
 if (object instanceof Path) {
  if (((Path)object).isDisposed ()) return;
  gc.drawPath ((Path) object);
  return;
 }
 if (object instanceof Pattern) {
  if (((Pattern)object).isDisposed ()) return;
  gc.setBackgroundPattern ((Pattern)object);
  gc.fillRectangle (canvas.getClientArea ());
  gc.setBackgroundPattern (null);
  return;
 }
 if (object instanceof Region) {
  if (((Region)object).isDisposed ()) return;
  String string = ((Region)object).getBounds().toString();
  gc.drawString (string, 0, 0);
  return;
 }
 if (object instanceof TextLayout) {
  if (((TextLayout)object).isDisposed ()) return;
  ((TextLayout)object).draw (gc, 0, 0);
  return;
 }
 if (object instanceof Transform) {
  if (((Transform)object).isDisposed ()) return;
  String string = ((Transform)object).toString();
  gc.drawString (string, 0, 0);
  return;
 }
}

void refreshObject () {
 int index = list.getSelectionIndex ();
 if (index == -1) return;
 if (check.getSelection ()) {
  ByteArrayOutputStream stream = new ByteArrayOutputStream ();
  PrintStream s = new PrintStream (stream);
  errors [index].printStackTrace (s);
  text.setText (stream.toString ());
  text.setVisible (true);
  canvas.setVisible (false);
 } else {
  canvas.setVisible (true);
  text.setVisible (false);
  canvas.redraw ();
 }
}

void refreshAll () {
 oldObjects = new Object [0];
 oldErrors = new Error [0];
 refreshDifference ();
 oldObjects = objects;
 oldErrors = errors;
}

void layout () {
 Rectangle rect = parent.getClientArea ();
 int width = 0;
 String [] items = list.getItems ();
 GC gc = new GC (list);
 for (int i=0; i<objects.length; i++) {
  width = Math.max (width, gc.stringExtent (items [i]).x);
 }
 gc.dispose ();
 Point size1 = start.computeSize (SWT.DEFAULT, SWT.DEFAULT);
 Point size2 = stop.computeSize (SWT.DEFAULT, SWT.DEFAULT);
 Point size3 = check.computeSize (SWT.DEFAULT, SWT.DEFAULT);
 Point size4 = label.computeSize (SWT.DEFAULT, SWT.DEFAULT);
 width = Math.max (size1.x, Math.max (size2.x, Math.max (size3.x, width)));
 width = Math.max (64, Math.max (size4.x, list.computeSize (width, SWT.DEFAULT).x));
 start.setBounds (0, 0, width, size1.y);
 stop.setBounds (0, size1.y, width, size2.y);
 check.setBounds (0, size1.y + size2.y, width, size3.y);
 label.setBounds (0, rect.height - size4.y, width, size4.y);
 int height = size1.y + size2.y + size3.y;
 list.setBounds (0, height, width, rect.height - height - size4.y);
 text.setBounds (width, 0, rect.width - width, rect.height);
 canvas.setBounds (width, 0, rect.width - width, rect.height);
}
}
==============
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.*;

/**
 * This sample class demonstrates how to plug-in a new
 * workbench view. The view shows data obtained from the
 * model. The sample creates a dummy model on the fly,
 * but a real implementation would connect to the model
 * available either in this or another plug-in (e.g. the workspace).
 * The view is connected to the model using a content provider.
 * <p>
 * The view uses a label provider to define how model
 * objects should be presented in the view. Each
 * view can present the same model objects using
 * different labels and icons, if needed. Alternatively,
 * a single label provider can be shared between views
 * in order to ensure that objects of the same type are
 * presented in the same way everywhere.
 * <p>
 */

public class SleakView extends ViewPart {

 Composite parent = null;
 Sleak sleak = null;

 /**
  * The constructor.
  */
 public SleakView() {
 }

 /**
  * This is a callback that will allow us
  * to create the viewer and initialize it.
  */
 public void createPartControl(Composite parent) {
  this.parent = parent;
  sleak = new Sleak ();
  sleak.open(parent);
  sleak.layout();
 }

 /**
  * Passing the focus request to the viewer's control.
  */
 public void setFocus() {
 }

}

================

可以把以上两个类copy到自己的工程下面,扩展一个view 结点,指定实现类为SleakView 就可以了。
<extension
         point="org.eclipse.ui.views">
      <category
            id="org.xxx.xxx.rcp.category"
            name="Sleak 工具">
      </category>
      <view
            category="org.xxx.xxx.rcp.category"
            class="org.xxx.xxx.rcp.sleak.SleakView"
            id="org.eclipse.swt.sleak.views.SleakView"
            name="Sleak00kaelS"
            restorable="true">
      </view>
   </extension>

这样在你运行你的项目的时候就可看到Sleak View了,能够很容易跟踪handler的消耗。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics