以下描述绝对适用于Eclipse RCP程序,稍作改动应该可以适用于SWT程序。
背景以及问题简单描述:
SWT中的每一个Widget,Font,Image,Color等等,引用的资源都是OS Resource,而不仅仅是Java世界所拥有的。
我相信我们的RCP程序,SWT程序肯定会用到这些东西。这些东西跟Java Objects不同的地方是,Java Objects在不用
的时候(置为null)会被GC回收,而这些OS Resource不会被GC回收。
32Bit的OS 为每一个Process分配的handles数目是10000,Windows OS 可以查看注册表:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\ CurrentVersion\Windows\ USERProcessHandleQuota and GDIProcessHandleQuota
在Google上搜索 SWT No more handles 很容易搜到SWT 官方提供的一些资料,我大致说下我看后对主要问题的理解:
Rule 1: If you created it, you dispose it.
Rule 2: Disposing the parent disposes the children.
我们很可能在不经意间已经直接或间接调用了一些资源的create方法,而我们没有注意他们的 javadoc:如果你调用这个方法,你有责任调用dispose方法来释放资源。
这样的话,就出现了资源(句柄)泄漏。如何检测我们的程序是否有资源泄漏呢?用Sleak。
下面的可看可不看,是我在探索问题过程中发给组内同事的mail内容
体会:
Rule1: 如果我们显示的调用了类如: Image image = new Image(…); 的代码的话,我们需要手动调用image.dispose(); 否则每次new Image()都是一个资源泄漏
关于Image对象,比如我们有一个方法:
public static void createImages(ImageData imageData, int i ) {
Image image = new Image(display, imageData);
System.out.println("image " + i);
image = null;
//image.dispose();
}
循环10000次,这个方法在执行第3313次的时候,出现了Exception in thread "main" org.eclipse.swt.SWTError: No more handles
如果启用 image.dispose(), 则没有问题。
Text 和 Label,这样的资源,通过在一个Editor中加入下面的代码:
for (int i = 0; i< 10000; i++) {
Text text = new Text (shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
System.out.println("text " + i);
}
这段代码在执行第9987次的时候,出现了 Exception in thread "main" org.eclipse.swt.SWTError: No more handles
通过上述可知No more handles 很容易重现,原因也很清楚:句柄不够用,Rule2有部分意思是说如何释放占用的句柄。
Rule2: 在一个Editor打开的代码中,插入代码:
for (int i = 0; i< 4600; i++) {
Text text = new Text (shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
System.out.println("text " + i);
}
当第一次尝试打开editor的时候,没有问题;
第二次尝试打开,也没有问题;(此时有两个Editor窗口实例)
第三次,提示”No more handles”;
关闭第一个窗口,再尝试打开第三个,此时没有问题。
说明,关闭第一个editor后,editor中的(子)资源得以释放。