<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:70.85pt 70.85pt 70.85pt 70.85pt;}
div.WordSection1
{page:WordSection1;}
--></style>
</head>
<body lang="FR" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal"><span style="mso-fareast-language:EN-US">Ron,<o:p></o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Indeed, it’s different with normal warmup as you suspected.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">The threshold is between 500 and 600 loops (not fully reproducible).<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">After around 600 iterations, the bigBuffer is not retained, so it’s good.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Test code below.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">So it mitigates my concern of retained objects in sync code vs retained in async code, but I think it’s still maybe not ideal since method compilation is related to CPU cost and not
memory usage. (“capture” behavior on suspended stack call should be more predictable and unrelated to JIT, like for lambda.)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">thanks<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Arnaud<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">------
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">import java.lang.management.ManagementFactory;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">import java.util.Timer;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">import java.util.TimerTask;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">import java.util.concurrent.ExecutionException;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">import java.util.concurrent.ExecutorService;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">import java.util.concurrent.Executors;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">public class Main1b {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> static int iter = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> static final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> public static void main(String[] args) throws ExecutionException, InterruptedException {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> var timer = new Timer();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> var memBean = ManagementFactory.getMemoryMXBean();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> timer.schedule(new TimerTask() {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> @Override<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> public void run() {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> System.gc();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> System.out.println("--- " + memBean.getHeapMemoryUsage());<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> }, 5_000, 5_000);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> for (int i=0; i<600; i++) // ******* warmup ******<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> myApp(0, 0);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> myApp(Long.MAX_VALUE, 1024 * 1024 * 1024);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> private static void myApp(long durationMs, int buffSize) throws ExecutionException, InterruptedException {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> var future = executor.submit(() -> {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> try {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> iter ++;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> System.out.println("Starting work, iter #" + iter);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> var bigBuffer = new byte[buffSize];<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> System.out.println("bigBuffer size: " + bigBuffer.length);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> // bigBuffer = null;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> slowIO(durationMs);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> } catch (InterruptedException e) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> throw new RuntimeException(e);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> });<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> future.get();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> private static void slowIO(long durationMs) throws InterruptedException {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> System.out.println("Starting slowIO");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> Thread.sleep(durationMs);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin-left:35.4pt"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>Can you test with C2 engaged normally through warmup?<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>On 8 Nov 2022, at 13:56, Arnaud Masson <arnaud.masson@fr.ibm.com> wrote:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>> I will check if C2 helps, but afaik since it’s triggered when method is<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>> used often (not because the method consumes significant memory), it’s<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>> not ideal to count on it anyway. Moreover, I suspect it’s not documented<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>> public behavior while lambda capture is well defined.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>I have checked the following example with (no debugger)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>--enable-preview<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>-XX:-TieredCompilation<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>-Xbatch<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>-Xcomp<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>-Xlog:nmethod+install<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>… to force C2, but the bigBuffer is still retained.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">>(Won’t C2 clear a stack ref only if it can be reused in the same scope for another java var?)<o:p></o:p></span></p>
<p class="MsoNormal">> <o:p></o:p></p>
<p class="MsoNormal">>Thanks<o:p></o:p></p>
<p class="MsoNormal">>Arnaud<o:p></o:p></p>
</div>
<DIV>
Unless otherwise stated above:<BR>
<BR>
Compagnie IBM France<BR>
Siège Social : 17, avenue de l'Europe, 92275 Bois-Colombes Cedex<BR>
RCS Nanterre 552 118 465<BR>
Forme Sociale : S.A.S.<BR>
Capital Social : 664 069 390,60 €<BR>
SIRET : 552 118 465 03644 - Code NAF 6203Z<BR>
</DIV></body>
</html>