Spasojevic, Daniel wrote:Are you up for working through this with diffs etc?
Yes, I think I can handle it, and I'd be only too happy to lend a hand.Thanks Daniel,
Here we go. I've attached a patch that makes the EventListenerMememto in the
BridgeContext use SoftReferences. The reason the patch is so large is that it also refactors
the ReferenceQueue threads out of the existing TileMap, and SoftReferenceCache
(for some reason I never thought to subclass SoftReference - the new system does and
there by greatly simplifies the code). The patch 'creates' a new file batik.util.CleanerThread
so you may need to set some options on your patch to get it to run.
Unfortunately by watching the CleanerThread I know that this does not solve the problem.
Can you use JProfiler to figure out who owns the arrays and the HashTable that
references it? I suspect there may be something in the DOM which keeps any nodes from
being GC'ed.
Index: sources/org/apache/batik/bridge/BridgeContext.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/BridgeContext.java,v
retrieving revision 1.62
diff -w -u -r1.62 BridgeContext.java
--- sources/org/apache/batik/bridge/BridgeContext.java 11 Jun 2003 22:07:24 -0000
1.62
+++ sources/org/apache/batik/bridge/BridgeContext.java 17 Jun 2003 10:54:53 -0000
@@ -12,6 +12,7 @@
import java.awt.geom.Dimension2D;
import java.io.IOException;
import java.io.InterruptedIOException;
+import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
@@ -37,6 +38,7 @@
import org.apache.batik.script.Interpreter;
import org.apache.batik.script.InterpreterPool;
import org.apache.batik.util.CSSConstants;
+import org.apache.batik.util.CleanerThread;
import org.apache.batik.util.ParsedURL;
import org.apache.batik.util.SVGConstants;
import org.apache.batik.util.Service;
@@ -883,7 +885,25 @@
String s,
EventListener l,
boolean b) {
- eventListenerList.add(new EventListenerMememto(t, s, l, b));
+ eventListenerList.add(new EventListenerMememto(t, s, l, b, this));
+ }
+
+ public static class SoftReferenceMememto
+ extends CleanerThread.SoftReferenceCleared {
+
+ Object mememto;
+ List list;
+ SoftReferenceMememto(Object ref, Object mememto, List list) {
+ super(ref);
+ this.mememto = mememto;
+ this.list = list;
+ }
+
+ public void cleared() {
+ list.remove(mememto);
+ mememto = null;
+ list = null;
+ }
}
/**
@@ -891,21 +911,37 @@
*/
protected static class EventListenerMememto {
- public EventTarget target;
- public EventListener listener;
+ public SoftReference target; // Soft ref to EventTarget
+ public SoftReference listener; // Soft ref to EventListener
public boolean useCapture;
public String eventType;
public EventListenerMememto(EventTarget t,
String s,
EventListener l,
- boolean b) {
- target = t;
+ boolean b,
+ BridgeContext ctx) {
+ List list = ctx.eventListenerList;
+ target = new SoftReferenceMememto(t, this, list);
+ listener = new SoftReferenceMememto(l, this, list);
eventType = s;
- listener = l;
useCapture = b;
}
+
+ public EventListener getListener() {
+ return (EventListener)listener.get();
+ }
+ public EventTarget getTarget() {
+ return (EventTarget)target.get();
+ }
+ public boolean getUseCapture() {
+ return useCapture;
}
+ public String getEventType() {
+ return eventType;
+ }
+ }
+
/**
* Disposes this BridgeContext.
@@ -916,9 +952,13 @@
Iterator iter = eventListenerList.iterator();
while (iter.hasNext()) {
EventListenerMememto m = (EventListenerMememto)iter.next();
- m.target.removeEventListener(m.eventType,
- m.listener,
- m.useCapture);
+ EventTarget et = m.getTarget();
+ EventListener el = m.getListener();
+ boolean uc = m.getUseCapture();
+ String t = m.getEventType();
+ if ((et == null) || (el == null) || (t == null))
+ continue;
+ et.removeEventListener(t, el, uc);
}
EventTarget evtTarget = (EventTarget)document;
Index: sources/org/apache/batik/ext/awt/image/rendered/TileMap.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/rendered/TileMap.java,v
retrieving revision 1.9
diff -w -u -r1.9 TileMap.java
--- sources/org/apache/batik/ext/awt/image/rendered/TileMap.java 11 Apr 2003
13:58:01 -0000 1.9
+++ sources/org/apache/batik/ext/awt/image/rendered/TileMap.java 17 Jun 2003
10:54:55 -0000
@@ -10,23 +10,31 @@
import java.awt.Point;
import java.awt.image.Raster;
-import java.lang.ref.Reference;
-import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
+import org.apache.batik.util.CleanerThread;
+
public class TileMap implements TileStore {
private static final boolean DEBUG = false;
private static final boolean COUNT = false;
- private static ReferenceQueue queue = new ReferenceQueue();
-
- private static HashMap items =new HashMap();
private HashMap rasters=new HashMap();
static class TileMapLRUMember extends TileLRUMember {
public Point pt;
public SoftReference parent;
+
+ class RasterSoftRef extends CleanerThread.SoftReferenceCleared {
+ RasterSoftRef(Object o) { super(o); }
+ public void cleared() {
+ if (DEBUG) System.err.println("Cleaned: " + this);
+ TileMap tm = (TileMap)parent.get();
+ if (tm != null)
+ tm.rasters.remove(pt);
+ }
+ };
+
TileMapLRUMember(TileMap parent, Point pt, Raster ras) {
super(ras);
this.parent = new SoftReference(parent);
@@ -35,12 +43,7 @@
public void setRaster(Raster ras) {
hRaster = ras;
- synchronized (items) {
- if (wRaster != null)
- items.remove(wRaster);
- wRaster = new SoftReference(ras, queue);
- items.put(wRaster, this);
- }
+ wRaster = new RasterSoftRef(ras);
}
}
@@ -135,35 +138,4 @@
static int requests;
static int misses;
-
- static Thread cleanup;
-
- static {
- cleanup = new Thread() {
- public void run() {
- while(true) {
- Reference ref;
-
- try {
- ref = queue.remove();
- } catch (InterruptedException ie) {
- continue;
- }
- synchronized (items) {
- Object o = items.remove(ref);
- if (DEBUG) System.out.println("Cleaning: " + o);
- if (o == null) continue;
-
- TileMapLRUMember item = (TileMapLRUMember)o;
- TileMap parent = (TileMap)item.parent.get();
- if (parent != null)
- parent.rasters.remove(item.pt);
- }
- }
- }
- };
- cleanup.setDaemon(true);
- cleanup.start();
- }
-
}
Index: sources/org/apache/batik/util/CleanerThread.java
===================================================================
RCS file: sources/org/apache/batik/util/CleanerThread.java
diff -N sources/org/apache/batik/util/CleanerThread.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sources/org/apache/batik/util/CleanerThread.java 17 Jun 2003 10:54:56 -0000
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package org.apache.batik.util;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.ref.PhantomReference;
+
+/**
+ * One line Class Desc
+ *
+ * Complete Class Desc
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]>l449433</a>
+ * @version $Id: skel.el,v 1.1 2003/05/13 21:04:46 deweese Exp $
+ */
+public class CleanerThread extends Thread {
+
+ static ReferenceQueue queue = null;
+ static CleanerThread thread = null;
+
+ public static ReferenceQueue getReferenceQueue() {
+ if (queue != null)
+ return queue;
+
+ queue = new ReferenceQueue();
+ thread = new CleanerThread();
+ return queue;
+ }
+
+ /**
+ * If objects registered with the reference queue associated with
+ * this class implement this interface then the 'cleared' method
+ * will be called when the reference is queued.
+ */
+ public static interface ReferenceCleared {
+ /* Called when the reference is cleared */
+ public void cleared();
+ }
+
+ /**
+ * A SoftReference subclass that automatically registers with
+ * the cleaner ReferenceQueue.
+ */
+ public static abstract class SoftReferenceCleared extends SoftReference
+ implements ReferenceCleared {
+ public SoftReferenceCleared(Object o) {
+ super (o, CleanerThread.getReferenceQueue());
+ }
+ }
+
+ /**
+ * A WeakReference subclass that automatically registers with
+ * the cleaner ReferenceQueue.
+ */
+ public static abstract class WeakReferenceCleared extends WeakReference
+ implements ReferenceCleared {
+ public WeakReferenceCleared(Object o) {
+ super (o, CleanerThread.getReferenceQueue());
+ }
+ }
+
+ /**
+ * A PhantomReference subclass that automatically registers with
+ * the cleaner ReferenceQueue.
+ */
+ public static abstract class PhantomReferenceCleared
+ extends PhantomReference
+ implements ReferenceCleared {
+ public PhantomReferenceCleared(Object o) {
+ super (o, CleanerThread.getReferenceQueue());
+ }
+ }
+
+ protected CleanerThread() {
+ setDaemon(true);
+ start();
+ }
+
+ public void run() {
+ while(true) {
+ Reference ref;
+ try {
+ ref = queue.remove();
+ // System.err.println("Cleaned: " + ref);
+ } catch (InterruptedException ie) {
+ continue;
+ }
+
+ if (ref instanceof ReferenceCleared) {
+ ReferenceCleared rc = (ReferenceCleared)ref;
+ rc.cleared();
+ }
+ }
+ }
+};
Index: sources/org/apache/batik/util/SoftReferenceCache.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/SoftReferenceCache.java,v
retrieving revision 1.4
diff -w -u -r1.4 SoftReferenceCache.java
--- sources/org/apache/batik/util/SoftReferenceCache.java 11 Apr 2003 13:59:29
-0000 1.4
+++ sources/org/apache/batik/util/SoftReferenceCache.java 17 Jun 2003 10:54:56
-0000
@@ -9,7 +9,6 @@
package org.apache.batik.util;
import java.lang.ref.Reference;
-import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
@@ -149,69 +148,29 @@
*/
protected final synchronized void putImpl(Object key, Object object) {
if (map.containsKey(key)) {
- SoftReference ref = new SoftReference(object, queue);
+ SoftReference ref = new SoftRefKey(object, key);
map.put(key, ref);
- synchronized (refMap) {
- refMap.put(ref, new Info(key, this));
- }
this.notifyAll();
}
}
- static class Info {
+ class SoftRefKey extends CleanerThread.SoftReferenceCleared {
Object key;
- SoftReference cacheRef;
- public Info(Object key,
- SoftReferenceCache cache) {
+ public SoftRefKey(Object o, Object key) {
+ super(o);
this.key = key;
- this.cacheRef = new SoftReference(cache);
- }
-
- public Object getKey() { return key; }
-
- public SoftReferenceCache getCache() {
- return (SoftReferenceCache)cacheRef.get();
- }
- }
-
- private static HashMap refMap = new HashMap();
- private static ReferenceQueue queue = new ReferenceQueue();
- private static Thread cleanup;
-
- static {
- cleanup = new Thread() {
- public void run() {
- while(true) {
- Reference ref;
- try {
- ref = queue.remove();
- } catch (InterruptedException ie) {
- continue;
- }
-
- Object o;
- synchronized (refMap) {
- o = refMap.remove(ref);
}
- // System.out.println("Cleaning: " + o);
- if (o == null) continue;
- Info info = (Info)o;
- SoftReferenceCache cache = info.getCache();
- if (cache == null) continue;
+ public void cleared() {
+ SoftReferenceCache cache = SoftReferenceCache.this;
+ if (cache == null) return; // Can't really happen.
synchronized (cache) {
- o = cache.map.remove(info.getKey());
- if (ref != o)
+ Object o = cache.map.remove(key);
+ if (this != o)
// Must not have been ours put it back...
// Can happen if a clear is done.
- cache.map.put(info.getKey(), o);
+ cache.map.put(key, o);
}
}
}
- };
- cleanup.setDaemon(true);
- cleanup.start();
- }
-
-
}--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
