实现SWT资源的缓存和自动释放

本文详细介绍了SWT中创建的与操作系统相关的资源需要手动释放,并提供了使用Map管理资源和自动释放的方法。通过实现原理分析,展示了如何利用SWT特性在程序结束时自动释放资源。以ColorRegistry为例,说明了在组织资源缓存与自动释放过程中的应用。强调了资源及时释放的重要性,以避免程序崩溃。

*概述

---SWT中创建的与操作系统相关的资源需要手动释放,如Image,Font,GC等,从api的角度看,就是org.eclipse.swt.graphics.Resource的所有子类.

所以对于需要重复利用的资源,我们一般做法是定义一个Map管理这些资源,最后再释放,如下面的做法

ColorManager示例 /*
 * Copyright(C) 2010 Agree Tech, All rights reserved.
 * 
 * Created on 2010-9-7   by dzh
 */

package cn.com.agree.modeling;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;

public class ColorManager {
	private final Map<RGB,Color> colorMap =new HashMap<RGB,Color>();
	
	public Color getColor(RGB rgb){
		Color color =(Color) colorMap.get(rgb);
		if(color==null){
			color =new Color(Display.getDefault(),rgb);
            colorMap.put(rgb, color);
		}
		return color;	
	}
	
	public void dispose(){
		Iterator<Color> i =colorMap.values().iterator();
		while(i.hasNext()){
			i.next().dispose();
		}
		colorMap.clear();
	}
}

---还有另外一种方式,利用SWT的特性:每个SWT程序,都有一个Display对象,Display在UI开始时被创建,在程序结束时被释放,咱们看看Display提供了些什么.


*实现原理

---display释放调用过程分析

Device.dispose()->Display.release()->Display.disposeList执行,

Display片段/* Display Shutdown */
Runnable [] disposeList;//这是Display定义的一个数组

protected void release () {
	sendEvent (SWT.Dispose, new Event ());
	Shell [] shells = getShells ();
	for (int i=0; i<shells.length; i++) {
		Shell shell = shells [i];
		if (!shell.isDisposed ()) shell.dispose ();
	}
	if (tray != null) tray.dispose ();
	tray = null;
	if (taskBar != null) taskBar.dispose ();
	taskBar = null;
	while (readAndDispatch ()) {}
	if (disposeList != null) {
		for (int i=0; i<disposeList.length; i++) { //执行disposeList内容
			if (disposeList [i] != null) disposeList [i].run ();
		}
	}
	disposeList = null;
	synchronizer.releaseSynchronizer ();
	synchronizer = null;
	releaseDisplay ();
	super.release ();
}

---现在知道了,只要给数组添加java.lang.Runnable,在Runnable.run()实现资源释放,这样就实现了我们缓存和自动释放的目的.

添加Runnable/**
 * Causes the <code>run()</code> method of the runnable to
 * be invoked by the user-interface thread just before the
 * receiver is disposed.  Specifying a <code>null</code> runnable
 * is ignored.
 *
 * @param runnable code to run at dispose time.
 * 
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
 * </ul>
 */
public void disposeExec (Runnable runnable) { //添加runnable
	checkDevice ();
	if (disposeList == null) disposeList = new Runnable [4];
	for (int i=0; i<disposeList.length; i++) {
		if (disposeList [i] == null) {
			disposeList [i] = runnable;
			return;
		}
	}
	Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
	System.arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
	newDisposeList [disposeList.length] = runnable;
	disposeList = newDisposeList;
}

*示例分析

---jface根据上面介绍的原理,在org.eclipse.jface.resource下提供了对需要释放资源的缓存类

---以org.eclipse.jface.resource.ColorRegistry为例,看看实现方式

ColorRegistry示例    /**
     * Collection of <code>Color</code> that are now stale to be disposed when 
     * it is safe to do so (i.e. on shutdown).
     */
    private List staleColors = new ArrayList(); //缓存资源

    /**
     * Table of known colors, keyed by symbolic color name (key type: <code>String</code>,
     * value type: <code>org.eclipse.swt.graphics.Color</code>.
     */
    private Map stringToColor = new HashMap(7);
   /**
     * Runnable that cleans up the manager on disposal of the display.
     */

     
    //定义Runnable
    protected Runnable displayRunnable = new Runnable() { 
        public void run() {
            clearCaches(); //释放资源
        }
    };

    public ColorRegistry(Display display, boolean cleanOnDisplayDisposal) {
		Assert.isNotNull(display);
        this.display = display;
        this.cleanOnDisplayDisposal = cleanOnDisplayDisposal;
        if (cleanOnDisplayDisposal) {
			hookDisplayDispose();  //将runnable添加到Display释放数组中
		}
    }
    /**
     * Hook a dispose listener on the SWT display.
     */
    private void hookDisplayDispose() {
        display.disposeExec(displayRunnable);
    }


*总结

---由于资源创建过多,没有及时释放,或者遗漏需要释放的资源,会导致"no more handlers"异常,以致程序崩溃.

所以缓存能提升性能,避免忘记释放,但是要注意在恰当的时候就及时释放.

转载于:https://www.cnblogs.com/bronte/articles/2083037.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值