Hi,

this was the simplest fix (actually workaround) for the memory leak we
were seeing with the FontPeers. It just keeps a least recently used
cache of AffineTransform mappings to TransformAttributes to use in the
font maps. That way we use the same fontpeer whenever all attributes are
the same (which wasn't true for the TextAttribute.TRANSFORM since
TransformAttribute doesn't implement equals and is final, so it was not
easy to check whether two TransformAttributes in font attribute maps
were equal.

2007-04-12  Mark Wielaard  <[EMAIL PROTECTED]>

    * gnu/java/awt/peer/ClasspathFontPeer.java (LRUCache): New static
    inner class.
    (transCache): New static LRUChache field.
    (copyTransformToAttrs): Check whether a TransformAttribute already
    exists in the transCache for the given AffineTransform.

This is a nice patch since it equalizes font attributes maps which means
that in GtkToolkit we will reuse the same FontPeer. Which in practise
stops the leak. So I am going to commit this to the trunk and release
branch. But the real solution to the leak in FontPeer would be to figure
out why the result of pango_context_load_fontset () isn't released when
the FontPeer is garbage collected.

Cheers,

Mark
Index: gnu/java/awt/peer/ClasspathFontPeer.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/ClasspathFontPeer.java,v
retrieving revision 1.10
diff -u -r1.10 ClasspathFontPeer.java
--- gnu/java/awt/peer/ClasspathFontPeer.java	2 Nov 2006 17:13:51 -0000	1.10
+++ gnu/java/awt/peer/ClasspathFontPeer.java	11 Apr 2007 23:41:16 -0000
@@ -54,6 +54,7 @@
 import java.text.AttributedCharacterIterator;
 import java.text.CharacterIterator;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Locale;
 import java.util.Map;
 
@@ -120,6 +121,23 @@
    */
   protected AffineTransform transform;
 
+  static class LRUCache<K,V> extends LinkedHashMap<K,V>
+  {
+    int max_entries;
+    public LRUCache(int max)
+    {
+      super(max, 0.75f, true);
+      max_entries = max;
+    }
+    protected boolean removeEldestEntry(Map.Entry eldest)
+    {
+      return size() > max_entries;
+    }
+  }
+
+  private static LRUCache<AffineTransform,TransformAttribute> transCache =
+    new LRUCache<AffineTransform,TransformAttribute>(50);
+
   protected static ClasspathToolkit tk()
   {
     return (ClasspathToolkit)(Toolkit.getDefaultToolkit ());
@@ -200,7 +218,19 @@
   protected static void copyTransformToAttrs (AffineTransform trans, Map attrs)
   {
     if (trans != null)
-      attrs.put(TextAttribute.TRANSFORM, new TransformAttribute (trans));
+      {
+	TransformAttribute ta;
+        synchronized(transCache)
+          {
+	    ta = transCache.get(trans);
+	    if (ta == null)
+	      {
+		ta = new TransformAttribute(trans);
+		transCache.put(trans, ta);
+	      }
+	  }
+	attrs.put(TextAttribute.TRANSFORM, ta);
+      }
   }
 
 

Reply via email to