From 0e58847d8d341b70734576aa813f755d9a716a18 Mon Sep 17 00:00:00 2001 From: Stefan Starke Date: Tue, 8 Oct 2019 13:27:41 +0200 Subject: 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 Signed-off-by: Alexander Kriegisch --- .../weaver/reflect/Java15AnnotationFinder.java | 53 ++++++++++++++++------ 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'weaver') diff --git a/weaver/src/main/java/org/aspectj/weaver/reflect/Java15AnnotationFinder.java b/weaver/src/main/java/org/aspectj/weaver/reflect/Java15AnnotationFinder.java index dfddd18da..ef437b724 100644 --- a/weaver/src/main/java/org/aspectj/weaver/reflect/Java15AnnotationFinder.java +++ b/weaver/src/main/java/org/aspectj/weaver/reflect/Java15AnnotationFinder.java @@ -42,9 +42,17 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { private Repository bcelRepository; private BcelWeakClassLoaderReference classLoaderRef; + + private static Repository staticBcelRepository; + private static BcelWeakClassLoaderReference staticClassLoaderRef; + private World world; private static boolean useCachingClassLoaderRepository; + //Use single instance of Repository and ClassLoader + public static final boolean useSingleInstances = + System.getProperty("org.aspectj.apache.bcel.useSingleRepositoryInstance", "true").equalsIgnoreCase("true"); + static { try { useCachingClassLoaderRepository = System.getProperty("Xset:bcelRepositoryCaching","true").equalsIgnoreCase("true"); @@ -58,14 +66,31 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { } public void setClassLoader(ClassLoader aLoader) { - this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader); + //Set class loader ref + if (useSingleInstances && staticClassLoaderRef == null) + staticClassLoaderRef = new BcelWeakClassLoaderReference(aLoader); + else + this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader); + + //Set repository if (useCachingClassLoaderRepository) { - this.bcelRepository = new ClassLoaderRepository(classLoaderRef); - } else { - this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef); + if (useSingleInstances && staticBcelRepository == null) + staticBcelRepository = new ClassLoaderRepository(getClassLoader()); + else + this.bcelRepository = new ClassLoaderRepository(getClassLoader()); + } + else { + if (useSingleInstances && staticBcelRepository == null) + staticBcelRepository = new NonCachingClassLoaderRepository(getClassLoader()); + else + this.bcelRepository = new NonCachingClassLoaderRepository(getClassLoader()); } } + private Repository getBcelRepository() { + return useSingleInstances ? staticBcelRepository : bcelRepository; + } + public void setWorld(World aWorld) { this.world = aWorld; } @@ -112,7 +137,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { } private ClassLoader getClassLoader() { - return classLoaderRef.getClassLoader(); + return useSingleInstances ? staticClassLoaderRef.getClassLoader() : classLoaderRef.getClassLoader(); } public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) { @@ -145,7 +170,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { anns = bcelField.getAnnotations(); } // the answer is cached and we don't want to hold on to memory - bcelRepository.clear(); + getBcelRepository().clear(); // OPTIMIZE make constant 0 size array for sharing if (anns == null) anns = AnnotationGen.NO_ANNOTATIONS; @@ -164,7 +189,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { public String getAnnotationDefaultValue(Member onMember) { try { - JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass()); + JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass()); if (onMember instanceof Method) { org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember); @@ -200,7 +225,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { // we can just use reflection. if (!areRuntimeAnnotationsSufficient) { try { - JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass()); + JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass()); org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = null; if (onMember instanceof Method) { org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember); @@ -215,7 +240,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { anns = bcelField.getAnnotations(); } // the answer is cached and we don't want to hold on to memory - bcelRepository.clear(); + getBcelRepository().clear(); if (anns == null || anns.length == 0) { return ResolvedType.NONE; } @@ -246,9 +271,9 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { // annotations so we bail out to Bcel and then chuck away the JavaClass so that we // don't hog memory. try { - JavaClass jc = bcelRepository.loadClass(forClass); + JavaClass jc = getBcelRepository().loadClass(forClass); org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations(); - bcelRepository.clear(); + getBcelRepository().clear(); if (anns == null) { return ResolvedType.NONE; } else { @@ -276,7 +301,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { return null; try { - JavaClass jc = bcelRepository.loadClass(forMember.getDeclaringClass()); + JavaClass jc = getBcelRepository().loadClass(forMember.getDeclaringClass()); LocalVariableTable lvt = null; int numVars = 0; if (forMember instanceof Method) { @@ -320,7 +345,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { // don't hog // memory. try { - JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass()); + JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass()); org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null; if (onMember instanceof Method) { org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember); @@ -340,7 +365,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { // anns = null; } // the answer is cached and we don't want to hold on to memory - bcelRepository.clear(); + getBcelRepository().clear(); if (anns == null) return NO_PARAMETER_ANNOTATIONS; ResolvedType[][] result = new ResolvedType[anns.length][]; -- cgit v1.2.3