Description
Please see the comment https://issues.apache.org/jira/browse/BCEL-317?focusedCommentId=16879552&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-16879552 for resolution.
Follow-up of BCEL-186. This enhancement is to provide an option to cache ConstantUtf8 instances that have the same value.
Email thread: [bcel] Idea to share ConstantUtf8 of same value among JavaClass instances
--------------------
We use BCEL library to inspect Java class. Thank you for the great library.
When our tool checks classes in ~200 jar files, it creates more than 2 million BCEL ConstantUtf8 instances. I suspect many of them share the same values such as "java.lang.String".
Without cache, my tool created 2,6 million ConstantUtf8 instances (before failing OutOfMemoryError: GC overhead limit exceeded) to check ~200 jar files.
With the cache, my tool created just 0.6 million ConstantUtf8 instances. It didn't throw the OutOfMemoryError.
Old commit that made ConstantUtf8.getInstance https://svn.apache.org/viewvc/commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/Constant.java?r1=1481383&r2=1481382&pathrev=1481383
The ConstantUtf8.getInstance has been unused in BCEL since BCEL-186 http://svn.apache.org/viewvc/commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/ConstantUtf8.java?r1=1652541&r2=1652540&pathrev=1652541
How our project uses BCEL
- Our tool (Linkage Checker) creates BCEL's ClassPathRepository with around 200 JAR files as its input class path in ClassDumper.createClassRepository(source code URL)
private static Repository createClassRepository(List<Path> paths) { ClassPath classPath = new LinkageCheckClassPath(paths); return new ClassPathRepository(classPath); # This is BCEL API }
- reads JavaClasses one by one in ClassDumper.listClassesInJar (source code URL) through the ClassPathRepository.
private ImmutableSet<JavaClass> listClassesInJar(Path jar) throws IOException { ImmutableSet.Builder<JavaClass> javaClasses = ImmutableSet.builder(); for (String className : listClassNamesInJar(jar)) { try { JavaClass javaClass = classRepository.loadClass(className); # This is BCEL API. ConstantUtf8 is not cached. javaClasses.add(javaClass); ...(omit) return javaClasses.build(); }
Stacktrace from the ClassDumper.listClassesInJar to BCEL's ConstantUtf8.getInstance would look like this:
ConstantUtf8.getInstance Constant.readConstant ConstantPool.<init> ClassParser.readConstantPool ClassParser.parse ClassPathRepository.loadClass ClassPathRepository.loadClass ClassDumper.listClassesInJar
- Use the JavaClass instances to check if any symbol references (entries in constant pool Java Virtual Machine Specification 4.4. The Constant Pool: CONSTANT_Class, CONSTANT_Fieldref, CONSTANT_Methodref, and CONSTANT_InterfaceMethodref) has invalid referent in the class path.