`
brandNewUser
  • 浏览: 446354 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

eclipse插件开发中资源释放问题

阅读更多

1.问题提出

在插件开发代码中,大量使用了图片作为图标,在相应的vieweditor中展示,初始时测试还OK,但是经过长时间的使用后,经常报出SWTNo More Handlers的错误,异常如下所示:

 

!ENTRY org.eclipse.osgi 4 0 2013-07-30 15:49:55.671
!MESSAGE Application error
!STACK 1
org.eclipse.swt.SWTError: No more handles
 at org.eclipse.swt.SWT.error(SWT.java:3803)
 at org.eclipse.swt.graphics.Image.init(Image.java:1582)
 at org.eclipse.swt.graphics.Image.<init>(Image.java:177)
 at org.eclipse.swt.widgets.Composite.WM_PAINT(Composite.java:1367)
 at org.eclipse.swt.widgets.Control.windowProc(Control.java:3842)
 at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:337)
 at org.eclipse.swt.widgets.Display.windowProc(Display.java:4541)
 at org.eclipse.swt.internal.win32.OS.UpdateWindow(Native Method)
 at org.eclipse.swt.widgets.Decorations.setVisible(Decorations.java:1389)
 at org.eclipse.swt.widgets.Shell.setVisible(Shell.java:1764)
 at org.eclipse.swt.widgets.Shell.open(Shell.java:1150)
 at org.eclipse.jface.window.Window.open(Window.java:797)
 at org.eclipse.ui.internal.WorkbenchWindow.open(WorkbenchWindow.java:778)
 at org.eclipse.ui.internal.Workbench$61.runWithException(Workbench.java:3402)
 at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
 at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
 at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:133)
 at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3800)
 at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3425)
 at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
 at org.eclipse.ui.internal.Workbench$27.runWithException(Workbench.java:1363)
 at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
 at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
 at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:133)
 at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3800)
 at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3425)
 at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2295)
 at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2200)
 at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:495)
 at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:288)
 at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:490)
 at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
 at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
 at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:193)
 at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
 at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
 at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:386)
 at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:549)
 at org.eclipse.equinox.launcher.Main.basicRun(Main.java:504)
 at org.eclipse.equinox.launcher.Main.run(Main.java:1236)
……

 

  

 

 

经过排查以及从网上学习了解到,SWT/JFace中的图片资源是需要自己管理释放的。

 

2.问题分析

Java开发人员在使用SWT/JFACE的时候,并不能借助于Java内置的垃圾回收机制来彻底完成系统资源的清理(Java虚拟机只能帮助我们释放虚拟机内存中的系统资源句柄引用对象)。在SWT中系统资源对象的定级类型是org.eclipse.swt.graphics.Resource,在类型明确说明了“Resources created by the application must be disposed”

 

eclipse插件开发的时候,很多地方都需要用到图片之类的资源,而在SWT中图片资源是需要手动释放的。手动释放时机却很难把握,尤其是图片可能被多个地方用到的时候。可以参考:http://southking.iteye.com/blog/316449对资源的解释,下面就说一下如何经过代码改动来避免资源释放问题。

 

下面列出几个比较容易出现句柄(本例子中是Image图片资源)数量超出的地方代码:

 

构造函数直接创建

 

 

new Image(Device device, InputStream stream)

 

 

通过ImageDescriptor+Path直接创建Image

private Image getImage(String path){ 
   ImageDescriptor desc = AbstractUIPlugin.imageDescriptorFromPlugin(ID, path); 
   return desc.createImage(); 
}  
 

通过ImageDescriptor+URL直接创建Image

private Image getImage(String path){ 
  URL url = null; 
  try{ 
   url = new URL(Activator.getDefault().getDescriptor().getInstallURL(), path); 
  }catch(MalformedURLException e){ 
   e.printStackTrace(); 
  } 
  ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(url); 
  return imageDescriptor.createImage(); 
 }  
 

 

3.问题处理

JFaceResourcesJFace中的资源管理门面类,由它获取我们的图片资源并进行缓存,相应的处理方法如下,写在对应bundleActivator中,使用JFacesResources来对ImageDescriptor中的Image进行缓存操作。

 

 

/**
    * 懒加载的方式添加Image资源的处理
    * @param imageFilePath
    * @return
    */
   public static Image imageFromPlugin(String imageFilePath) {
      Image image = JFaceResources.getImageRegistry().get(imageFilePath);
      if(image != null) {
         return image;
      } else {
         ImageDescriptor imageDescriptorFromPlugin = imageDescriptorFromPlugin(PLUGIN_ID(本插件的ID), imageFilePath);
         image = imageDescriptorFromPlugin.createImage();
         JFaceResources.getImageRegistry().put(imageFilePath, image);
         return image;
      }
   }
 

 

使用这种方式时,注意一点,Activator中的stop方法手动将资源管理器中的资源释放掉:

public void stop(BundleContext bundleContext) throws Exception {
      JFaceResources.getImageRegistry().dispose();
      Activator.context = null;
      plugin = null;
   }
 

 

此后在使用图片资源时,都使用了这种方式,通过Activator. imageFromPlugin(imageFilePath)获取Image对象。

 

当然有些接口中要求返回的是ImageDescriptor,直接调用

ImageDescriptor org.eclipse.ui.plugin.AbstractUIPlugin.imageDescriptorFromPlugin(String pluginId, String imageFilePath)

方法即可,不会造成No more handlers错误。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics