diff options
author | Stefan Starke <stefan@starkeweb.org> | 2019-10-08 13:27:41 +0200 |
---|---|---|
committer | Andy Clement <aclement@pivotal.io> | 2022-01-13 15:07:30 -0800 |
commit | 0e58847d8d341b70734576aa813f755d9a716a18 (patch) | |
tree | 393edd496668ea365780412d10b40e94ee7ac963 /bcel-builder | |
parent | 1b3cead1715cd4f233d81c88ba7a33dc1aa59886 (diff) | |
download | aspectj-0e58847d8d341b70734576aa813f755d9a716a18.tar.gz aspectj-0e58847d8d341b70734576aa813f755d9a716a18.zip |
Optimize class loading
In our project we found out that during the build up of the spring context
the class loading takes a very long time.
Root cause is the huge amount of file I/O during pointcut class loading.
We are taking about ~250k file loads.
With these changes we managed to cut down the starting time by around 50%.
What we found out is that IMHO - the clear method of the ClassLoaderRepository
is called far too often -> in our settings this resulted in not a single cache
hit as the cache got cleared permanently.
Therefore we de-actived the cache clear calls inside the ClassLoaderRepository.
Secondly we changed the Java15AnnotationFinder in a way to not always create
new objects for the ClassLoaderRepository but re-use one static instance.
Otherwise we experienced >100k objects being created.
Last but not least we introduced a cache for unavailable classes so that
they do not have to be looked up using file I/O over and over again.
The whole behavior is configurable via
+ org.aspectj.apache.bcel.useSingleRepositoryInstance (default: true)
+ org.aspectj.apache.bcel.useUnavailableClassesCache (default: true)
+ org.aspectj.apache.bcel.ignoreCacheClearRequests (default: true)
Signed-off-by: Stefan Starke <stefan@starkeweb.org>
Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
Diffstat (limited to 'bcel-builder')
-rw-r--r-- | bcel-builder/src/main/java/org/aspectj/apache/bcel/util/ClassLoaderRepository.java | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/bcel-builder/src/main/java/org/aspectj/apache/bcel/util/ClassLoaderRepository.java b/bcel-builder/src/main/java/org/aspectj/apache/bcel/util/ClassLoaderRepository.java index e16d0efff..cdc072b5c 100644 --- a/bcel-builder/src/main/java/org/aspectj/apache/bcel/util/ClassLoaderRepository.java +++ b/bcel-builder/src/main/java/org/aspectj/apache/bcel/util/ClassLoaderRepository.java @@ -64,6 +64,7 @@ import java.net.URLClassLoader; import java.util.AbstractMap; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; @@ -95,6 +96,16 @@ public class ClassLoaderRepository implements Repository { public static boolean useSharedCache = System.getProperty("org.aspectj.apache.bcel.useSharedCache", "true").equalsIgnoreCase("true"); + //Cache not found classes as well to prevent unnecessary file I/O operations + public static final boolean useUnavailableClassesCache = + System.getProperty("org.aspectj.apache.bcel.useUnavailableClassesCache", "true").equalsIgnoreCase("true"); + //Ignore cache clear requests to not build up the cache over and over again + public static final boolean ignoreCacheClearRequests = + System.getProperty("org.aspectj.apache.bcel.ignoreCacheClearRequests", "true").equalsIgnoreCase("true"); + + //Second cache for the unavailable classes + private static Set<String> unavailableClasses = new HashSet<String>(); + private static int cacheHitsShared = 0; private static int missSharedEvicted = 0; // Misses in shared cache access due to reference GC private long timeManipulatingURLs = 0L; @@ -183,8 +194,10 @@ public class ClassLoaderRepository implements Repository { @Override public void clear() { - processQueue(); - map.clear(); + if (!ignoreCacheClearRequests) { + processQueue(); + map.clear(); + } } @Override @@ -281,12 +294,19 @@ public class ClassLoaderRepository implements Repository { */ public JavaClass loadClass(String className) throws ClassNotFoundException { + //Quick evaluation of unavailable classes to prevent unnecessary file I/O + if (useUnavailableClassesCache && unavailableClasses.contains(className)) + throw new ClassNotFoundException(className + " not found."); + // translate to a URL long time = System.currentTimeMillis(); java.net.URL url = toURL(className); timeManipulatingURLs += (System.currentTimeMillis() - time); - if (url == null) + if (url == null) { + if (useUnavailableClassesCache) + unavailableClasses.add(className); throw new ClassNotFoundException(className + " not found - unable to determine URL"); + } JavaClass clazz = null; @@ -314,6 +334,9 @@ public class ClassLoaderRepository implements Repository { InputStream is = (useSharedCache ? url.openStream() : loaderRef.getClassLoader().getResourceAsStream( classFile + ".class")); if (is == null) { + if (useUnavailableClassesCache) { + unavailableClasses.add(className); + } throw new ClassNotFoundException(className + " not found using url " + url); } ClassParser parser = new ClassParser(is, className); @@ -326,6 +349,7 @@ public class ClassLoaderRepository implements Repository { classesLoadedCount++; return clazz; } catch (IOException e) { + unavailableClasses.add(className); throw new ClassNotFoundException(e.toString()); } } @@ -384,10 +408,12 @@ public class ClassLoaderRepository implements Repository { /** Clear all entries from the local cache */ public void clear() { - if (useSharedCache) - sharedCache.clear(); - else - localCache.clear(); + if (!ignoreCacheClearRequests) { + if (useSharedCache) + sharedCache.clear(); + else + localCache.clear(); + } } } |