Skip to content

Commit

Permalink
Reduce memory usage for ClassLoaderHasClassesNamedMatcher
Browse files Browse the repository at this point in the history
  • Loading branch information
laurit committed Feb 21, 2023
1 parent 4607fcf commit 6f4cf22
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@
public final class ClassLoaderMatcherCacheHolder {

@GuardedBy("allCaches")
private static final List<Cache<ClassLoader, Boolean>> allCaches = new ArrayList<>();
private static final List<Cache<ClassLoader, ?>> allCaches = new ArrayList<>();

private ClassLoaderMatcherCacheHolder() {}

public static void addCache(Cache<ClassLoader, Boolean> cache) {
public static void addCache(Cache<ClassLoader, ?> cache) {
synchronized (allCaches) {
allCaches.add(cache);
}
}

public static void invalidateAllCachesForClassLoader(ClassLoader loader) {
synchronized (allCaches) {
for (Cache<ClassLoader, Boolean> cache : allCaches) {
for (Cache<ClassLoader, ?> cache : allCaches) {
cache.remove(loader);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@
import io.opentelemetry.instrumentation.api.internal.cache.Cache;
import io.opentelemetry.javaagent.bootstrap.internal.ClassLoaderMatcherCacheHolder;
import io.opentelemetry.javaagent.bootstrap.internal.InClassLoaderMatcher;
import java.util.BitSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import net.bytebuddy.matcher.ElementMatcher;

class ClassLoaderHasClassesNamedMatcher extends ElementMatcher.Junction.AbstractBase<ClassLoader> {

private final Cache<ClassLoader, Boolean> cache = Cache.weak();
private static final AtomicInteger counter = new AtomicInteger();

private final String[] resources;
private final int index = counter.getAndIncrement();

ClassLoaderHasClassesNamedMatcher(String... classNames) {
resources = classNames;
for (int i = 0; i < resources.length; i++) {
resources[i] = resources[i].replace(".", "/") + ".class";
}
ClassLoaderMatcherCacheHolder.addCache(cache);
Manager.INSTANCE.add(this);
}

@Override
Expand All @@ -30,10 +34,10 @@ public boolean matches(ClassLoader cl) {
// Can't match the bootstrap class loader.
return false;
}
return cache.computeIfAbsent(cl, this::hasResources);
return Manager.INSTANCE.match(this, cl);
}

private boolean hasResources(ClassLoader cl) {
private static boolean hasResources(ClassLoader cl, String... resources) {
boolean priorValue = InClassLoaderMatcher.getAndSet(true);
try {
for (String resource : resources) {
Expand All @@ -46,4 +50,41 @@ private boolean hasResources(ClassLoader cl) {
}
return true;
}

private static class Manager {
private static final BitSet EMPTY = new BitSet(0);
static final Manager INSTANCE = new Manager();
private final List<ClassLoaderHasClassesNamedMatcher> matchers = new CopyOnWriteArrayList<>();
private final Cache<ClassLoader, BitSet> enabled = Cache.weak();
private volatile boolean matchCalled = false;

Manager() {
ClassLoaderMatcherCacheHolder.addCache(enabled);
}

void add(ClassLoaderHasClassesNamedMatcher matcher) {
if (matchCalled) {
throw new IllegalStateException("All matchers should be create before match is called");
}
matchers.add(matcher);
}

boolean match(ClassLoaderHasClassesNamedMatcher matcher, ClassLoader cl) {
matchCalled = true;
BitSet set = enabled.get(cl);
if (set == null) {
set = new BitSet(counter.get());
for (ClassLoaderHasClassesNamedMatcher m : matchers) {
if (hasResources(cl, m.resources)) {
set.set(m.index);
}
}
enabled.put(cl, set.isEmpty() ? EMPTY : set);
enabled.put(cl, set);
} else if (set.isEmpty()) {
return false;
}
return set.get(matcher.index);
}
}
}

0 comments on commit 6f4cf22

Please sign in to comment.