garbage collection and indy

Jochen Theodorou blackdrag at gmx.org
Thu Aug 24 08:18:27 UTC 2023



Am 24.08.23 um 06:10 schrieb John Rose:
> I am not following every detail here, but as long as you have a variable
> and/or an indy state that gives access to any part of a dynamically
> loaded class, then that class will not be unloaded.  There’s no way
> to unload most of a class but keep one of its methods, for example.
> And if the class is live, its class loader will be live as well.
>
> So, indy or field -> MH or VH -> class -> loader is the chain
> that keeps everything alive.

To confirm the second part of my assumptions:

void foo() {
   ClassLoader classloader = new UrlClassLoader(...)
   Runnable script = (Runnable) classloader.load("SC").newInstance()
   script.run() // plain invokevirtual now
   script = null
   classloader = null
}

Under the assumption that classloader is the defining loader for SC, as
soon as the foo() call is completed the SC class becomes in theory
collectable, even though the class containing foo still lives, because
neither callsite nor internal structures for the invokevirtual will
reference on SC in a way, that keeps SC alive. there has to be some kind
of reference somewhere I assume, otherwise nothing would know about SC
being used multiple times in the callsite (even though the scenario here
actually makes this impossible).


If that callsite would be naively implemented using invokedynamic and a
mutable callsite and runtime method selection I could end up with a
handle SC#run, which will keep SC alive.

In the example here there is the option of producing a handle
Runnable#run instead, which I strongly assume would not keep the class
SC alive.

That means if I want to implement

def foo(x) {
   x.run()
}

in Groovy where I know nothing about what x really is until I am past
the invocation of the initial handle I have now the problem of creating
a handle for this callsite, which does not prevent GC from collecting
the class SC, nor do I want to create the handle again if the next call
is on the exact same SC. I may have no knowledge as of if SC is intended
to stay or not.

So what I am currently thinking that is required is a method handles
variant of this kind of code:


def invoke(Object[] argumentsAndReceiver, ClassValue boundClassValue) {
   MethodHandle handle =
boundClassValue.get(argumentsAndReceiver[0].getClass())
   handle.invokeExcat(argumentsAndReceiver);
}

Of course now I am wondering if there is still any ability to inline,
since the handle that is returned is in Groovy already quite complex.
Actually it would be good to know what I must not do if I want any
chance of inlining happening. Because so far I have not really found any
limits ever. I mean that is one of the primary purposes of the Class
according to the Javadoc... just I always get nervous when I see
volatiles, AtomicIntegers and map strcutures involved as my past
experience with invokevirtual was, that a lot of these are inlining
barriers. But this kind of practical knowledge is most likely outdated.

This kind of handling could also result in a million or two ClassValue
objects as each callsite would have one. No idea what the GC will say to
that.

bye Jochen


More information about the mlvm-dev mailing list