<div dir="ltr"><div><p>Hi Valhalla Development Team,</p>
<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>
<pre class="gmail-overflow-visible!"><div class="gmail-contain-inline-size gmail-rounded-2xl gmail-relative gmail-bg-token-sidebar-surface-primary"><div class="gmail-sticky gmail-top-9"><div class="gmail-absolute end-0 gmail-bottom-0 gmail-flex gmail-h-9 gmail-items-center gmail-pe-2"><div class="gmail-bg-token-bg-elevated-secondary gmail-text-token-text-secondary gmail-flex gmail-items-center gmail-gap-4 gmail-rounded-sm gmail-px-2 gmail-font-sans gmail-text-xs"></div></div></div><div class="gmail-overflow-y-auto gmail-p-4" dir="ltr"><code class="gmail-whitespace-pre! gmail-language-java"><span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">class</span> <span class="gmail-hljs-title gmail-class_">ValhallaTest</span> {
    value <span class="gmail-hljs-keyword">record</span> <span class="gmail-hljs-title gmail-class_">PointRecord</span><span class="gmail-hljs-params">(<span class="gmail-hljs-type">short</span></span> x, <span class="gmail-hljs-type">short</span> y, <span class="gmail-hljs-type">short</span> z) {}

    <span class="gmail-hljs-keyword">void</span> <span class="gmail-hljs-title gmail-function_">main</span><span class="gmail-hljs-params">()</span> <span class="gmail-hljs-keyword">throws</span> InterruptedException {
        Thread.sleep(<span class="gmail-hljs-number">9000</span>); <span class="gmail-hljs-comment">// allow time to attach VisualVM</span>
        System.out.println(<span class="gmail-hljs-string">"Starting"</span>);
        <span class="gmail-hljs-type">int</span> <span class="gmail-hljs-variable">size</span> <span class="gmail-hljs-operator">=</span> <span class="gmail-hljs-number">10_000_000</span>;
        <span class="gmail-hljs-type">var</span> <span class="gmail-hljs-variable">pointRecords</span> <span class="gmail-hljs-operator">=</span> <span class="gmail-hljs-keyword">new</span> <span class="gmail-hljs-title gmail-class_">PointRecord</span>[size];
        <span class="gmail-hljs-keyword">for</span> (<span class="gmail-hljs-type">int</span> <span class="gmail-hljs-variable">i</span> <span class="gmail-hljs-operator">=</span> <span class="gmail-hljs-number">0</span>; i < size; i++) {
            pointRecords[i] = <span class="gmail-hljs-keyword">new</span> <span class="gmail-hljs-title gmail-class_">PointRecord</span>((<span class="gmail-hljs-type">short</span>) <span class="gmail-hljs-number">2</span>, (<span class="gmail-hljs-type">short</span>) <span class="gmail-hljs-number">2</span>, (<span class="gmail-hljs-type">short</span>) <span class="gmail-hljs-number">3</span>);
        }
        Thread.sleep(<span class="gmail-hljs-number">20000</span>);
    }
}
</code></div></div></pre>
<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>
<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>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>
<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>
<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>
<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><br></div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div><br></div></div></div></div></div></div></div></div>