<div dir="ltr">Dear Rémi,<div><br></div><div>Thanks so much for the detailed reply and for clarifying some of my questions. Also, the -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlineLayout seems quite useful. It also shows layout has reserved space at the beginning, presumably when identity is required and lack of it if flattening happens (I guess, but still useful information). I wasn't aware null is embedded too. Was wondering why if a value object has an exact 32 bits (an int, e.g. new PointRecord(int x)), it's actual size is 64. The additional null marker makes sense why. Also, it seems null-restriction means better memory optimisation. I'll keep doing more test to learn more.<br><br>Regards</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Sun, 26 Oct 2025 at 17:38, Remi Forax <<a href="mailto:forax@univ-mlv.fr">forax@univ-mlv.fr</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><div style="font-family:arial,helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)"><div><br></div><div><br></div><hr id="m_7528639759773106898zwchr"><div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><b>From: </b>"Joe Mwangi" <<a href="mailto:joemwangimburu@gmail.com" target="_blank">joemwangimburu@gmail.com</a>><br><b>To: </b>"valhalla-dev" <<a href="mailto:valhalla-dev@openjdk.org" target="_blank">valhalla-dev@openjdk.org</a>><br><b>Sent: </b>Sunday, October 26, 2025 2:30:52 PM<br><b>Subject: </b>Observations and Questions on Flattening Behavior and Memory Alignment in Value Objects<br></blockquote></div><div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir="ltr"><div><p>Hi Valhalla Development Team,</p></div></div></blockquote><div><br></div><div>Hello Joe,</div><div>i'm not part of the implementation team (i'm part of the spec team), but i can answer to some of your questions,</div><div><br></div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir="ltr"><div><p>Thank you for providing the latest build for testing progress on value objects in the JVM. I’ve been running a few experiments to understand the behavior of custom value types and their memory characteristics, and I must say I’m very impressed by the implementation so far. Memory usage appears significantly reduced in many cases (sometimes to nearly ¾ of the original).</p><p>Here’s a simple test I used:</p><div><div dir="ltr"><code><span>public</span> <span>class</span> <span>ValhallaTest</span> {
    value <span>record</span> <span>PointRecord</span><span>(<span>short</span></span> x, <span>short</span> y, <span>short</span> z) {}

    <span>void</span> <span>main</span><span>()</span> <span>throws</span> InterruptedException {
        Thread.sleep(<span>9000</span>); <span>// allow time to attach VisualVM</span>
        System.out.println(<span>"Starting"</span>);
        <span>int</span> <span>size</span> <span>=</span> <span>10_000_000</span>;
        <span>var</span> <span>pointRecords</span> <span>=</span> <span>new</span> <span>PointRecord</span>[size];
        <span>for</span> (<span>int</span> <span>i</span> <span>=</span> <span>0</span>; i < size; i++) {
            pointRecords[i] = <span>new</span> <span>PointRecord</span>((<span>short</span>) <span>2</span>, (<span>short</span>) <span>2</span>, (<span>short</span>) <span>3</span>);
        }
        Thread.sleep(<span>20000</span>);
    }
}
</code></div></div><p>Using VisualVM, I inspected live objects and heap usage, with the following observations:</p><ol><li><p>No individual <code>PointRecord</code> objects were detected — only the <code>PointRecord[]</code> array, confirming full flattening (no identity objects).</p></li><li><p><code>PointRecord(short, short, short)</code> logically occupies 6 bytes, but the array reports <strong>80 000 000 B</strong> for 10 M elements → 8 bytes per element, suggesting alignment to 64 bits.</p></li></ol></div></div></blockquote><div><br></div><div><br></div><div>it's short + short + short + byte (for null) + alignment, hence 64 bits.<br><br></div><div dir="ltr"><div><ol><li><p><code>PointRecord(short x, short y)</code> → <strong>40 000 000 B</strong> → 4 bytes per element.</p></li><li><p><code>PointRecord(byte x)</code> → <strong>20 000 000 B</strong> → 2 bytes per element.</p></li></ol><p>> It appears the prototype aligns flattened array elements to the smallest power of two ≥ the logical size (not just 4-byte boundaries). Beyond 64 bits (≥ 8 bytes), flattening seems to stop, possibly reverting to identity semantics, which makes sense given mutation and tearing concerns.</p><p>So it's more than you need to add a bit (a byte) representing null and then it has to be a power of two (alignment) because you want to read the location in one read/write to avoid tearing.</p><p><br></p><p>> A few questions came up from these results:</p><ol><li><p>Will arrays need to be immutable to guarantee flattening for value elements larger than 64 bits? Think about parsing large files, where a large array with larger sized value object will be important, hence mutable array being key, and then do simd parsing.</p></li></ol></div></div><div><br></div><div>The array needs to have non-null elements, and you need a way to opt-out of atomicity (allow tearing).</div><div>The exact way to do the latter is still in flux.</div><div><br></div><div>About using simd, there is an issue because you can read/write using simd but then you need to extract the value from the simd register to a general purpose register and this is actually quite slow,</div><div>so the Hotspot does not do that.</div><div><br></div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir="ltr"><div><ol><li></li><li><p>Since value objects are scalarized across stack calls, will there be tooling to analyze whether scalarization actually occurs (e.g., register-based limits determined by the JVM, if not enough register space, value object gains identity)?</p></li></ol></div></div></blockquote><div><br></div><div>as far as i know, c2 (the only JIT that optimize value classes) will scalarize depending on the size of the instance but not depending on if you have not enough registers, the registers will be spilled on stack in that case.</div><div><br></div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir="ltr"><div><ol><li></li><li><p>In C, struct size can be predicted from field types. For Java value objects, since layout is JVM-dependent, is there a plan for tooling (perhaps <code>jcmd</code> or JFR integration) to expose explicit size/layout information beyond array inspection? The default above example shows that a 6 bytes size value object is actually 8 bytes, but in C, it shall remain 6 byte size.</p></li></ol></div></div></blockquote><div><br></div><div>you can use<span style="background-color:rgb(255,255,255)"> -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlineLayout but it only works for fields, not for arrays.</span></div><div><br></div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><div dir="ltr"><div><p>Overall, this is very exciting work. The model feels both efficient and semantically robust, offering a fresh take compared to languages that rely on purely compile-time memory determinism. I’ll continue exploring performance and GC interaction aspects later, but even this preliminary testing shows remarkable promise.</p><p>Thanks again to the entire team for the great work.</p><p>Kind regards,<br><strong>Joe Mwangi</strong></p></div></div></blockquote><div><br></div><div>regards,</div><div>Rémi</div><div><br></div></div></div></div></blockquote></div><div><br clear="all"></div><div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Joe Mwangi<div>Principal Scientist</div><div>Nuclear Power and Energy Agency (NuPEA)</div><div><br></div><div>Tel:          : +254701378543</div><div>Twitter      : <span style="color:rgb(0,153,51);font-family:arial,sans-serif;line-height:15px;background-color:rgb(255,255,255)"><a href="https://twitter.com/" target="_blank">https://twitter.com/</a></span><span style="color:rgb(0,153,51);font-family:arial,sans-serif;line-height:15px;background-color:rgb(255,255,255)">JoeMwangiMburu</span></div><div>Facebook :<font color="#33ff33"> </font><font color="#33cc00"><a href="https://www.facebook.com/joemwangimburu" target="_blank">https://www.facebook.com/joemwangimburu</a></font></div><div><font face="arial, sans-serif"><span style="line-height:15px">LinkedIn<font color="#009933">   :</font><font color="#009933"> <a href="http://www.linkedin.com/in/joemwangimburu" target="_blank">http://www.linkedin.com/in/joemwangimburu<br></a></font></span></font></div><div><font face="arial, sans-serif">NuPEA    : </font><a href="http://www.nuclear.co.ke/" target="_blank">http://www.nuclear.co.ke/</a> <br></div><div><br></div></div></div></div></div></div></div>