aboutsummaryrefslogtreecommitdiffstats
path: root/bcel-builder
diff options
context:
space:
mode:
authorStefan Starke <stefan@starkeweb.org>2019-10-08 13:27:41 +0200
committerAndy Clement <aclement@pivotal.io>2022-01-13 15:07:30 -0800
commit0e58847d8d341b70734576aa813f755d9a716a18 (patch)
tree393edd496668ea365780412d10b40e94ee7ac963 /bcel-builder
parent1b3cead1715cd4f233d81c88ba7a33dc1aa59886 (diff)
downloadaspectj-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.java40
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();
+ }
}
}