Question on Lambda function
Chen Liang
liangchenblue at gmail.com
Wed May 29 18:43:33 UTC 2024
Hi Gu,
CallSite is specific to each invokedynamic instruction instead of each
InvokeDynamic constant pool entry:
https://docs.oracle.com/javase/specs/jvms/se22/html/jvms-6.html#jvms-6.5.invokedynamic
And the linking is done by MethodHandleNatives.linkCallSite if you want to
follow the Java implementation code.
For why the lambda in the loop is constant, it's a feature from
InnerClassLambdaMetafactory:
https://github.com/openjdk/jdk/blob/c8eea59f508158075382079316cf0990116ff98e/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java#L236
When the lambda is non-capturing, the bootstrap method
LambdaMetafactory.metafactory will eagerly create a singleton instance and
return this singleton in the indy instruction.
Also, your metaspace pressure might be caused by the fact that Lambda
classes (not instances) are no longer eagerly unloaded; see
https://github.com/openjdk/jdk/pull/12493 and
https://bugs.openjdk.org/browse/JDK-8302154. You are recommended to create
your own facility to create hidden classes in Java 17 instead of continue
to use LambdaMetafactory explicitly in code.
Regards,
Chen Liang
On Wed, May 29, 2024 at 12:53 PM Zhengyu Gu <zhengyu.gu at servicenow.com>
wrote:
> Hello Lambda experts,
>
>
>
> Since we upgraded JDK from 11 to 17, we’re experiencing metaspace
> pressure, largely due to Lambda class implementation changes.
>
>
>
> There’s a scenario (see attached test case), that is especially puzzled
> me, hopefully, you can share some insights.
>
>
>
> In this test case, there is only one Lambda class is created inside the
> loop, but each one for the same functions outside loop.
>
>
>
> Example output:
>
>
>
> 0: Func = LambdaFunc$$Lambda/0x00001f80000c4a20 at 4de8b406
>
> testMethod() called
>
> 1: Func = LambdaFunc$$Lambda/0x00001f80000c4a20 at 4de8b406
>
> testMethod() called
>
> 2: Func = LambdaFunc$$Lambda/0x00001f80000c4a20 at 4de8b406
>
> testMethod() called
>
> 3: Func = LambdaFunc$$Lambda/0x00001f80000c4a20 at 4de8b406
>
> testMethod() called
>
> 4: Func = LambdaFunc$$Lambda/0x00001f80000c4a20 at 4de8b406
>
> testMethod() called
>
>
>
> ….
>
>
>
> Outside loop1, Func = LambdaFunc$$Lambda/0x00001f80000c4c58 at 402f32ff
>
> testMethod() called
>
> Outside loop2 Func = LambdaFunc$$Lambda/0x00001f80000d1000 at 5ae9a829
>
> testMethod() called
>
> Outside loop3 Func = LambdaFunc$$Lambda/0x00001f80000d1238 at 548b7f67
>
> testMethod() called
>
>
>
> And jcmd also confirmed there were 4 Lambda classes created:
>
>
>
> 49: CLD 0x000060000134cb50: "app" instance of
> jdk.internal.loader.ClassLoaders$AppClassLoader
>
> Loaded classes:
>
> 1: LambdaFunc$$Lambda/0x00001f80000d1238
>
> 2: LambdaFunc$$Lambda/0x00001f80000d1000
>
> 3: LambdaFunc$$Lambda/0x00001f80000c4c58
>
> 4: LambdaFunc$$Lambda/0x00001f80000c4a20
>
> 5: LambdaFunc
>
>
>
> Looking into bytecode, all four call sites have the same invokedynamic
> bytecode (invokedynamic #7, 0 // InvokeDynamic
> #0:run:()Ljava/lang/Runnable; ) and the first invokedynamic bytecode is
> inside the loop.
>
>
>
> But when I ran the program with -XX:+TraceBytecodes, it seems that the
> first invokedynamic was hoisted and result was used in the subsequence loop.
>
>
>
> Can anyone explain where this magic happens? If the magic can apply to
> the instances outside the loop, so that only one Lambda class is created?
>
>
>
>
>
> Thank you for your time and expertise,
>
>
>
> -Zhengyu
>
>
>
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240529/0f1171bf/attachment-0001.htm>
More information about the core-libs-dev
mailing list