Based on duncanIdaho’s ClassPath class, I modded this code. Aim is to “find all classes that are instances of a given interface or class” at runtime. I’d been using it OK for a while, and adding small fixes as problems came up (e.g. additional Throwable’s).
But now…I’m getting a massive memory leak, and no idea how to solve it. Mem usage goes from 64MB to over 160MB before process is killed - just from this one method.
Note that I ran this on the same PC 12 hours earlier wihtout problems, and it produce approx 4 classes as a result of the method (which is correct - there are only 4 test instances for the code I’m currently working with).
So…AFAICS there is no reason why this shouldn’t at the very least GC if it spirals out of control; I’ve checked that it (theoretically) isn’t hanging onto references.
EDIT: see the rest of thread for details, but basically the OOME is from too much method calling, hence sidesteps GC. Silly me can no longer recognise an infinite recusive loop in java runtimes (probably simply because it looks different in logging frameworks compared to in DOS prompt where I learnt it :))
I could try to limit by package name using the regex, but I’d like to be fully automatic and not rely on unreliable voluntary naming conventions! Meanwhile, any ideas on why this code OutOfMemoryError’s on 1.4.2_05 instead of GC’ing?
NB: ignore the poor package name; that was from before i got the JGF domain - it will be fixed before I post the JAR!
package com.grexengine.jgf;
import java.util.ArrayList;
import java.util.Iterator;
/**
* An essential part of Java - locates any Class, anywhere.
* </P>
* This feature would have been nice as part of the JDK for the last 7 years, but Sun hasn't
* added it, so we did it instead.
* <P>
* Browse the different static methods to see what kinds of search you can do...
*/
public class ClassLocater
{
/**
* Find all instances of the given <code>Class</code> or interface by
* loading all classes on the class path.
*
* @param targetType the superclass of all returned classes.
* @return an array of all subclasses of <code>targetType</code>
*/
public static Class[] getSubclassesOf( Class targetType )
{
return getSubclassesOf( targetType, ".*" );
}
/**
* Find all subclasses of the given <code>Class</code> or interface by
* loading only those classes with names that match the given regular
* expression.
*
* @param targetType the superclass of all returned classes.
* @param regex a regular expression that will match with every subclass
* @return an array of all subclasses of <code>targetType</code>
*/
public static Class[] getSubclassesOf( Class targetType, String regex )
{
ArrayList matches = new ArrayList();
ClassPath cp = new ClassPath();
Iterator i = cp.classNameIterator();
while ( i.hasNext() )
{
String className = (String)i.next();
if ( className.matches( regex )
&& !className.equals( targetType.getName() ) )
{
Class clazz = null;
try
{
clazz = Class.forName( className );
}
catch (ClassNotFoundException cnfx )
{
continue;
}
catch (NoClassDefFoundError cnfx )
{
continue;
}
catch( UnsatisfiedLinkError cnfx )
{
continue;
}
finally
{
if ( clazz != null && targetType.isAssignableFrom( clazz ) )
{
matches.add( clazz );
}
}
}
}
return (Class[])matches.toArray( new Class[0] );
}
}