K.Schmid
K.Schmid

Reputation: 11

throwaway classloaders with byte-buddy

In our application we are using certain classloaders for particular jobs (Eclipse environment). Byte Buddy is maintaining these classloaders and stores a reference on them in the class Nexus. We are closing and deleting these classloaders. But the references on these classloaders are still hold within the Nexus class. Is there a possibility to say ByteBuddy that a classloaders goes absolute and therefore can be deleted from the classloader collection maintained by ByteBuddy?

Upvotes: 1

Views: 516

Answers (1)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44032

The Nexus class serves as an intermediate dispatcher for classes that have an active initialization strategy. Classes are written into this nexus either because:

  1. You are using an AgentBuilder with an InitilaizationStrategy.SelfInjecting in addition to using an active LoadedTypeInitializer for this type.
  2. You are using TypeResolutionStrategy.Active when defining a new type.

In both cases, the Nexus receives an entry right before a class is loaded where the entry should be removed right after. The concept is as follows: Upon (1) or (2), before loading a class, Byte Buddy registers a loaded type initializer within the nexus:

LoadedTypeInitializer initializer = instrument("Foo");
Nexus.register("Foo", classLoaderOfFoo, 42);

In order to assure that the class is fully initialized (e.g. static fields are set), before any code is executed, Byte Buddy then adds the following code to the beginning of the type initializer:

class Foo {
  static {
    Nexus.initialize(Foo.class, 42);
  }
}

This way, Byte Buddy can assure that Foo is fully initialized before its first use.

Most likely, you do not run every instrumented class's initializer before disposing a class loader such that the references get stuck. I will think of a way to resolve this problem.

UPDATE: This is now possible and will be released as a part of Byte Buddy 1.5.5. Class loaders are now only referenced weakly by a Nexus and it is possible to register a custom InitializationStrategy.SelfInjection.Split (the default) which takes a NexusAccessor as a single argument. Such a nexus accessor allows the registration of a reference queue to clean up such references. For example:

ReferenceQueue<ClassLoader> refQueue = new ReferenceQueue<ClassLoader>();
NexusAccessor accessor = new NexusAccessor(refQueue);

new AgentBuilder.Default()
  .with(new AgentBuilder.InitializationStrategy.SelfInjection.Split(accessor));

Now, any reference that is registered within the nexus will be enqueued to refQueue once a class loader is garbage collected. You can remove such references from the nexus via NexusAccessor.clean(ref).

Upvotes: 1

Related Questions