install transformer takes too long time
My purpose is to hook some functions to implement monitoring. There are about 40 hook points. I am using the Advice method. When I do the installation of the hitch points, it takes a long time. Through debugging I found that the following function takes a long time. The main reason should be this for-for loop. There are about 27k classes in types. Moreover, I executed the installOn method about 40 times, which took too much time.
Is there a good way to optimize ?
Here is part of code.
private final AgentBuilder commonAgentBuilder = new AgentBuilder.Default()
.disableClassFormatChanges()
.ignore(ElementMatchers.none())
.ignore(ElementMatchers.nameStartsWith(ignorePackagesArray[0]))
.ignore(ElementMatchers.nameStartsWith(ignorePackagesArray[1]))
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE);
for (AdviceInfo advice : adviceInfo) {
AgentBuilder.Transformer transformer;
ResettableClassFileTransformer resetAgentBuilder;
transformer = new Transformer() {
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module, ProtectionDomain protectionDomain) {
return builder
.visit(net.bytebuddy.asm.Advice.to(MethodInterceptors.class)
.on(methodMatcher));
}
};
resetAgentBuilder = commonAgentBuilder
.type(classMatcher)
.transform(transformer)
.installOn(instrumentation);
}
Here is the function which takes long time.
net.bytebuddy.agent.builder.AgentBuilder.RedefinitionStrategy#apply
for (Iterable<Class<?>> types : redefinitionDiscoveryStrategy.resolve(instrumentation)) {
RedefinitionStrategy.Collector collector = make(...);
for (Class<?> type : types) { // types has 27k classes
if (...) {
continue;
}
collector.consider(type, DISPATCHER.isModifiableClass(instrumentation, type) || ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5).isAtMost(ClassFileVersion.JAVA_V5));
}
batch = collector.apply(instrumentation, redefinitionBatchAllocator, redefinitionListener, batch);
}
And the same to
for (Advice advice : adviceMap.values()) {
advice.getResetTransformer().reset(instrumentation, AgentBuilder.RedefinitionStrategy.RETRANSFORMATION);
}
You should concatenate the agent builder and only install it a single time after the loop. The transformations are additive by default.
Do u mean code like this?
for (AdviceInfo advice : adviceInfo) {
transformer = new Transformer() {...};
commonAgentBuilder
.type(classMatcher)
.transform(transformer)
}
resetAgentBuilder = commonAgentBuilder.installOn(instrumentation);
I tried it, it works but not obvious. Mainly I want to minimize the impact of too many classes (types). What should I do? Would it be more efficient to have the builder ignore more classes?
The fewer classes are transformed, the better. But retransforming is in itself expensive, so this reduces iterations by a lot.