<div dir="ltr">Hi Gu,<div>CallSite is specific to each invokedynamic instruction instead of each InvokeDynamic constant pool entry: <a href="https://docs.oracle.com/javase/specs/jvms/se22/html/jvms-6.html#jvms-6.5.invokedynamic">https://docs.oracle.com/javase/specs/jvms/se22/html/jvms-6.html#jvms-6.5.invokedynamic</a></div><div>And the linking is done by MethodHandleNatives.linkCallSite if you want to follow the Java implementation code.</div><div>For why the lambda in the loop is constant, it's a feature from InnerClassLambdaMetafactory: <a href="https://github.com/openjdk/jdk/blob/c8eea59f508158075382079316cf0990116ff98e/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java#L236">https://github.com/openjdk/jdk/blob/c8eea59f508158075382079316cf0990116ff98e/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java#L236</a></div><div>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.</div><div><br></div><div>Also, your metaspace pressure might be caused by the fact that Lambda classes (not instances) are no longer eagerly unloaded; see <a href="https://github.com/openjdk/jdk/pull/12493">https://github.com/openjdk/jdk/pull/12493</a> and <a href="https://bugs.openjdk.org/browse/JDK-8302154">https://bugs.openjdk.org/browse/JDK-8302154</a>. You are recommended to create your own facility to create hidden classes in Java 17 instead of continue to use LambdaMetafactory explicitly in code.</div><div><br></div><div>Regards,</div><div>Chen Liang</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, May 29, 2024 at 12:53 PM Zhengyu Gu <<a href="mailto:zhengyu.gu@servicenow.com">zhengyu.gu@servicenow.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="msg6268846199879253428">





<div lang="EN-US" style="overflow-wrap: break-word;">
<div class="m_-5447452561659455976WordSection1">
<div id="m_-5447452561659455976mail-editor-reference-message-container">
<div>
<div>
<p class="MsoNormal"><span style="font-family:Arial,sans-serif;color:rgb(34,34,34);background:white">Hello Lambda experts,</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">Since we upgraded JDK from 11 to 17, we’re experiencing metaspace pressure, largely due to Lambda class implementation changes.</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">There’s a scenario (see attached test case),  that is especially puzzled me, hopefully, you can share some insights.</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">In this test case, there is only one Lambda class is created inside the loop, but each one for the same functions outside loop.</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">Example output:</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">0: Func =  LambdaFunc$$Lambda/0x00001f80000c4a20@4de8b406</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">1: Func =  LambdaFunc$$Lambda/0x00001f80000c4a20@4de8b406</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">2: Func =  LambdaFunc$$Lambda/0x00001f80000c4a20@4de8b406</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">3: Func =  LambdaFunc$$Lambda/0x00001f80000c4a20@4de8b406</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">4: Func =  LambdaFunc$$Lambda/0x00001f80000c4a20@4de8b406</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt;font-family:Arial,sans-serif;color:rgb(34,34,34)"> </span><u></u><u></u></p>
<p class="MsoNormal">….<u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">Outside loop1, Func =  LambdaFunc$$Lambda/0x00001f80000c4c58@402f32ff</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">Outside loop2 Func = LambdaFunc$$Lambda/0x00001f80000d1000@5ae9a829</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">Outside loop3 Func = LambdaFunc$$Lambda/0x00001f80000d1238@548b7f67</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">testMethod() called</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">And jcmd also confirmed there were 4 Lambda classes created:</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">  49: CLD 0x000060000134cb50: "app" instance of jdk.internal.loader.ClassLoaders$AppClassLoader</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">      Loaded classes:</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">         1:    LambdaFunc$$Lambda/0x00001f80000d1238</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">         2:    LambdaFunc$$Lambda/0x00001f80000d1000
</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">         3:    LambdaFunc$$Lambda/0x00001f80000c4c58</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">         4:    LambdaFunc$$Lambda/0x00001f80000c4a20</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">         5:    LambdaFunc</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">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.</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">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.</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">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?</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">Thank you for your time and expertise,</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt">-Zhengyu</span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
<p class="MsoNormal"><span style="font-size:12pt"> </span><u></u><u></u></p>
</div>
</div>
</div>
</div>
</div>

</div></blockquote></div>