Hi John, Thanks for the detailed explanation.
I ran a few additional experiments after I wrote a simpler program to try to reproduce the issue. I don't see the permgen leak, so something else must be causing it in Presto. I do see the "Loaded..." messages without a corresponding "Unloaded...", so your hypothesis about that happening for anonymous classes seems likely. Interestingly, it has another side-effect: the "Loaded classes" counter in VisualVM and in the ClassLoadingMXBean don't seem to work correctly under this scenario. It also reproduces the issue I mentioned regarding seemingly duplicate LFs. The code is here if you want to take a quick look: https://github.com/martint/lftest. The weird behavior goes away if I change the indy callsite to return Object instead of String Thanks! Martin On Mon, Sep 8, 2014 at 6:29 PM, John Rose <john.r.r...@oracle.com> wrote: > Hi Martin. > > A few LFs are cached in 8u20, and many more will be in 8u40; those will > not be unloaded. > > A non-cached LF can be viewed as customized, to the exact MH that caused > its creation. > > It should be the case that a LF that is customized to LFs will be unloaded > (with its bytecodes) as soon as the last reference to it goes away. > > An indy instruction bound to a LF (via a call site and MH) will typically > be the only reference to the LF, so if the class containing the indy goes > away, the LF should go also. > > LF bytecodes are loaded with Unsafe.defineAnonymousClass, which means that > the class is not registered in any class loader or dictionary, but should > get unloaded as soon as everybody drops the java.lang.Class for the LF > bytecodes. A MH with anonymous bytecodes indirectly refers to the > java.lang.Class. > > All that's to say that you should not have a storage leak if your classes > are getting unloaded. (And if you don't cache MHs, etc.) If you have a > leak, there's either an inadvertent reference keeping the MH stuff alive, > or else there is a bug in the defineAnonymousClass mechanism. > > (I can't remember offhand whether anonymous classes report unload events. > If the reporting is coupled to the system dictionary, then you won't get a > report, since ACs don't affect the system dictionary.) > > But. The example you give below comes from MethodHandles.constant (a K > combinator instance). Those are cached, I think. They also should not be > numerous, since their types are erased to basic-types. > > The string inside the dummy method is intended to be human-readable > documentation of what the LF does. > > In this example, the class Species_L is a bound method handle containing > one reference field. Its method argL0 returns that unique value. (If it > also had a second double field, the method would be Species_LD.argD1, > etc.) The receiver argument of this LF (a0) is a one-field Species_L which > carries the constant K value in its argL0 field; when invoked, it returns > that value. > > If you have two LF classes with the same string, there might be bug. > > — John > > On Sep 8, 2014, at 4:54 PM, Martin Traverso <mtrave...@gmail.com> wrote: > > > Do the generated bytecodes for LambdaForms ever get unloaded? In Presto > (a distributed SQL engine) we generate bytecode on the fly for each query > and use invokedynamic in a number of places as a way to link constants. We > recently ran into a permgen leak (we run 7u45). Looking at the output of > -verbose:class, I noticed a bunch of lines like these: > > > > [Loaded java.lang.invoke.LambdaForm$MH227/995942612 from > java.lang.invoke.LambdaForm] > > [Loaded java.lang.invoke.LambdaForm$MH228/489675590 from > java.lang.invoke.LambdaForm] > > [Loaded java.lang.invoke.LambdaForm$MH229/2095286826 from > java.lang.invoke.LambdaForm] > > [Loaded java.lang.invoke.LambdaForm$MH230/538456879 from > java.lang.invoke.LambdaForm] > > [Loaded java.lang.invoke.LambdaForm$MH231/1550961803 from > java.lang.invoke.LambdaForm] > > ... > > > > We load our generated bytecode in standalone classloaders and it > eventually gets unloaded. I never see an unload message for the LambdaForm > classes, though. > > > > This is what’s inside one of those classes. They all look similar: > > > > > javap -c 'LambdaForm$MH499.class' > > > > Compiled from "LambdaForm$MH499" > > final class java.lang.invoke.LambdaForm$MH499 extends > java.lang.invoke.LambdaForm { > > static java.lang.Object identity(java.lang.Object); > > Code: > > 0: aload_0 > > 1: checkcast #12 // class > java/lang/invoke/BoundMethodHandle$Species_L > > 4: getfield #16 // Field > java/lang/invoke/BoundMethodHandle$Species_L.argL0:Ljava/lang/Object; > > 7: astore_1 > > 8: ldc #18 // String > CONSTANT_PLACEHOLDER_0 <<MethodHandle(Object)Object>> > > 10: checkcast #20 // class > java/lang/invoke/MethodHandle > > 13: aload_1 > > 14: invokevirtual #23 // Method > java/lang/invoke/MethodHandle.invokeBasic:(Ljava/lang/Object;)Ljava/lang/Object; > > 17: areturn > > > > static void dummy(); > > Code: > > 0: ldc #27 // String > identity=Lambda(a0:L)=>{\n t1:L=Species_L.argL0(a0:L);\n > t2:L=ValueConversions.identity(t1:L);t2:L} > > 2: pop > > 3: return > > } > > _______________________________________________ > > mlvm-dev mailing list > > mlvm-dev@openjdk.java.net > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > _______________________________________________ > mlvm-dev mailing list > mlvm-dev@openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev >
_______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev