IntrospectionHelper keeps a cache of helpers it has made for particular Class's. This cache is cleared (presumably to avoid leaking memory) when the build finishes - *if* callers have used the factory method IH.getHelper(Project,Class) rather than the IH.gH(Class) variant. Unfortunately, if you call only IH.gH(Class) then the Class references are not released, even by a build finish event. This appears to have caused a massive memory leak in the JVM permanent generation (where classes are held) in the NetBeans IDE. (Workaround: forcibly clear the cache via reflection.) More: http://www.netbeans.org/issues/show_bug.cgi?id=43113 Better would be to use a WeakHashMap, since there is no reason to keep a cache entry if the Class key is referenced only from that entry; it could not possibly be used. Generally, please be very suspicious of any static fields, especially maps, and use weak references wherever appropriate. Attaching a patch which makes the cache weak on the key, and also uses the 2-arg variant of getHelper wherever it seems it would be possible. (There are some places where there is no Project context and it is not possible.)
Created attachment 12131 [details] Suggested patch
My apologies, private static Map/*<Class,IntrospectionHelper>*/ helpers = new WeakHashMap(); won't help since each IH holds a ref to the Class in the 'bean' field, which will prevent the Class from being collected.
Created attachment 12198 [details] Revised patch for just IntrospectionHelper.java to hold both keys and values weakly in helpers (does not include other classes listed in the previous patch)
Note that the revised patch lets IntrospectionHelper objects be collected even while the Class still exists, which may be undesirable since it could result in too much object recreation. I'm sure there's some trick which ReferenceQueue's which solves this...
Revising strategy a bit. I am unfortunately not aware of any way to prevent some IH objects from being collected on occasion while the Class still exists, since the IH must retain a reference to the Class (e.g. it holds Method's defined by it) - and Java provides no way to make two objects live or die as a pair. This could be problematic for performance. However the rest of the patch should still at least be an improvement - no one in main Ant code would be calling IH.gH(Class) any more. IH.gH(Project,Class) will still use a cache, but this is cleared when any build finishes (not necessarily the one that asked for the IH, by the way). Interactive environments such as NetBeans do have to call gh(Class), for purposes of code completion, as there is no associated project - so these IH instances will not be cached.
Checking in src/main/org/apache/tools/ant/IntrospectionHelper.java; /home/cvs/ant/src/main/org/apache/tools/ant/IntrospectionHelper.java,v <-- IntrospectionHelper.java new revision: 1.94; previous revision: 1.93 done Checking in src/main/org/apache/tools/ant/ProjectHelper.java; /home/cvs/ant/src/main/org/apache/tools/ant/ProjectHelper.java,v <-- ProjectHelper.java new revision: 1.115; previous revision: 1.114 done Checking in src/main/org/apache/tools/ant/UnknownElement.java; /home/cvs/ant/src/main/org/apache/tools/ant/UnknownElement.java,v <-- UnknownElement.java new revision: 1.88; previous revision: 1.87 done More commits to come... Checking in src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java; /home/cvs/ant/src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java,v <-- ProjectHelperImpl.java new revision: 1.30; previous revision: 1.29 done More commits to come... Checking in src/main/org/apache/tools/ant/taskdefs/AntStructure.java; /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/AntStructure.java,v <-- AntStructure.java new revision: 1.44; previous revision: 1.43 done