On Thu, 9 Feb 2023 18:11:18 GMT, Volker Simonis <simo...@openjdk.org> wrote:
>> Prior to >> [JDK-8239384](https://bugs.openjdk.org/browse/JDK-8239384)/[JDK-8238358](https://bugs.openjdk.org/browse/JDK-8238358) >> LambdaMetaFactory has created VM-anonymous classes which could easily be >> unloaded once they were not referenced any more. Starting with JDK 15 and >> the new "hidden class" based implementation, this is not the case any more, >> because the hidden classes will be strongly tied to their defining class >> loader. If this is the default application class loader, these hidden >> classes can never be unloaded which can easily lead to Metaspace exhaustion >> (see the [test case in the JBS >> issue](https://bugs.openjdk.org/secure/attachment/102601/LambdaClassLeak.java)). >> This is a regression compared to previous JDK versions which some of our >> applications have been affected from when migrating to JDK 17. >> >> The reason why the newly created hidden classes are strongly linked to their >> defining class loader is not clear to me. JDK-8239384 mentions it as an >> "implementation detail": >> >>> *4. the lambda proxy class has the strong relationship with the class >>> loader (that will share the VM metaspace for its defining loader - >>> implementation details)* >> >> From my current understanding the strong link between a hidden class created >> by `LambdaMetaFactory` and its defining class loader is not strictly >> required. In order to prevent potential OOMs and fix the regression compared >> the JDK 14 and earlier I propose to create these hidden classes without the >> `STRONG` option. >> >> I'll be happy to add the test case as JTreg test to this PR if you think >> that would be useful. > > Volker Simonis has updated the pull request incrementally with two additional > commits since the last revision: > > - Remove assertions which insist on Lambda proxy classes being strongly > linked to their class loader > - Removed unused import of STRONG und updated copyright year Even in JDK 11, a lambda proxy classes that's referenced by the cpCache (i.e., from a resolved invokedynamic instruction associated with a lamda expression) is always kept alive. See test below. So if I understand correctly, this patch will not affect lamda expressions in Java source code. It affects only direct calls to `LambdaMetafactory.metafactory()`. Is this correct? public class LambdaGC { public static void main(String[] args) throws Throwable { System.out.println("Entering LambdaGC"); doit(() -> { Thread.dumpStack(); }); for (int i = 0; i < 10; i++) { System.gc(); } System.out.println("Finish LambdaGC"); } static void doit(Runnable r) { r.run(); } } $ java11 -cp . -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -Xlog:class+load -Xlog:class+unload LambdaGC | grep LambdaGC [0.022s][info][class,load] LambdaGC source: file:/jdk3/tmp/ Entering LambdaGC [0.024s][info][class,load] LambdaGC$$Lambda$1/0x0000000840060840 source: LambdaGC java.lang.Exception: Stack trace at java.base/java.lang.Thread.dumpStack(Thread.java:1387) at LambdaGC.lambda$main$0(LambdaGC.java:5) at LambdaGC$$Lambda$1/0x0000000840060840.run(<Unknown>:1000000) at LambdaGC.doit(LambdaGC.java:13) at LambdaGC.main(LambdaGC.java:4) Finish LambdaGC ------------- PR: https://git.openjdk.org/jdk/pull/12493