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); + } }