Skip to content

Commit d359c67

Browse files
committed
Use a soft-value cache in the class repository, this resolves the memory-leaking issues that the original repository has.
1 parent b9bdff9 commit d359c67

6 files changed

Lines changed: 60 additions & 6 deletions

File tree

src/main/java/nl/rug/jbi/jsm/core/JSMCore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package nl.rug.jbi.jsm.core;
22

33
import com.google.common.base.Preconditions;
4-
import nl.rug.jbi.jsm.bcel.CompositeBCELClassLoader;
4+
import nl.rug.jbi.jsm.util.CompositeBCELClassLoader;
55
import nl.rug.jbi.jsm.core.calculator.BaseMetric;
66
import nl.rug.jbi.jsm.core.calculator.MetricCollection;
77
import nl.rug.jbi.jsm.core.calculator.MetricScope;

src/main/java/nl/rug/jbi/jsm/core/execution/ControllerThread.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ public void run() {
215215
}
216216

217217
executorPool.shutdown();
218+
repo.clear();
218219

219220
executionPlan.onFinish();
220221
}

src/main/java/nl/rug/jbi/jsm/core/execution/PipelineExecutor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package nl.rug.jbi.jsm.core.execution;
22

33
import com.google.common.base.Preconditions;
4-
import nl.rug.jbi.jsm.bcel.CompositeBCELClassLoader;
54
import nl.rug.jbi.jsm.core.calculator.MetricResult;
65
import nl.rug.jbi.jsm.core.calculator.MetricScope;
76
import nl.rug.jbi.jsm.core.pipeline.HandlerMap;
87
import nl.rug.jbi.jsm.core.pipeline.Pipeline;
98
import nl.rug.jbi.jsm.core.pipeline.PipelineFrame;
109
import nl.rug.jbi.jsm.frontend.Frontend;
11-
import org.apache.bcel.util.ClassLoaderRepository;
10+
import nl.rug.jbi.jsm.util.CompositeBCELClassLoader;
11+
import nl.rug.jbi.jsm.util.SoftValueClassLoaderRepository;
1212
import org.apache.bcel.util.Repository;
1313
import org.apache.logging.log4j.LogManager;
1414
import org.apache.logging.log4j.Logger;
@@ -53,7 +53,7 @@ public PipelineExecutor(
5353
final ClassVisitorFactory cvFactory) {
5454
this.frontend = frontend;
5555
this.dataSource = dataSource;
56-
this.repo = new ClassLoaderRepository(dataSource);
56+
this.repo = new SoftValueClassLoaderRepository(dataSource);
5757
this.handlerMap = executionPlan.getHandlerMaps();
5858
this.frameMap = executionPlan.getPipelineFrames();
5959
this.cvFactory = cvFactory;

src/main/java/nl/rug/jbi/jsm/metrics/ClassSourceProducer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.google.common.base.Supplier;
44
import com.google.common.collect.Lists;
5-
import nl.rug.jbi.jsm.bcel.CompositeBCELClassLoader;
5+
import nl.rug.jbi.jsm.util.CompositeBCELClassLoader;
66
import nl.rug.jbi.jsm.bcel.JavaClassDefinition;
77
import nl.rug.jbi.jsm.core.calculator.MetricScope;
88
import nl.rug.jbi.jsm.core.calculator.MetricState;

src/main/java/nl/rug/jbi/jsm/bcel/CompositeBCELClassLoader.java renamed to src/main/java/nl/rug/jbi/jsm/util/CompositeBCELClassLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package nl.rug.jbi.jsm.bcel;
1+
package nl.rug.jbi.jsm.util;
22

33
import com.google.common.base.Preconditions;
44
import com.google.common.collect.Lists;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package nl.rug.jbi.jsm.util;
2+
3+
import com.google.common.cache.Cache;
4+
import com.google.common.cache.CacheBuilder;
5+
import org.apache.bcel.classfile.JavaClass;
6+
import org.apache.bcel.util.ClassLoaderRepository;
7+
8+
/**
9+
* Extended version of the default BCEL {@link org.apache.bcel.util.ClassLoaderRepository}.
10+
* <br>
11+
* The original version uses a hash map to store the previously loaded classes, this creates a java memory leak for
12+
* larger inspections, since those classes never get released during execution.
13+
* <br>
14+
* This implementation uses Guava's {@link com.google.common.cache.Cache} with soft-reference values so the JVM can
15+
* reclaim memory if it needs to, at the expense of slightly increasing class lookup time through this class.
16+
*
17+
* @author David van Leusen
18+
* @since 2014-07-14
19+
*/
20+
public class SoftValueClassLoaderRepository extends ClassLoaderRepository {
21+
private final Cache<String, JavaClass> classCache = CacheBuilder.newBuilder()
22+
.softValues()
23+
.build();
24+
25+
/**
26+
* @param loader The class loader from which to load class-data.
27+
*/
28+
public SoftValueClassLoaderRepository(final ClassLoader loader) {
29+
super(loader);
30+
super.clear();
31+
}
32+
33+
@Override
34+
public void storeClass(JavaClass clazz) {
35+
classCache.put(clazz.getClassName(), clazz);
36+
clazz.setRepository(this);
37+
}
38+
39+
@Override
40+
public void removeClass(JavaClass clazz) {
41+
classCache.invalidate(clazz.getClassName());
42+
}
43+
44+
@Override
45+
public JavaClass findClass(String className) {
46+
return classCache.getIfPresent(className);
47+
}
48+
49+
@Override
50+
public void clear() {
51+
classCache.invalidateAll();
52+
}
53+
}

0 commit comments

Comments
 (0)