<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jvm on tsvinc</title>
    <link>https://tsvinc.dev/tags/jvm/</link>
    <description>Recent content in Jvm on tsvinc</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 07 Jul 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://tsvinc.dev/tags/jvm/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Native Image Grew to 734 MB</title>
      <link>https://tsvinc.dev/posts/five-numbers-18-branches/</link>
      <pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/five-numbers-18-branches/</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 20 of &lt;a href=&#34;https://tsvinc.dev/series/micronaut-256mb/&#34;&gt;the Micronaut native image series&lt;/a&gt;. Field notes from running benchmark scenarios across 18 branches — three frameworks, three runtimes, four memory tiers. No narrative arc. Just five things that surprised me.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-native-is-not-automatically-small&#34;&gt;1. Native is not automatically small&lt;/h2&gt;&#xA;&lt;p&gt;The pitch: GraalVM native images are lean. Sub-100 MB footprint. Container-friendly. Cloud-native.&lt;/p&gt;&#xA;&lt;p&gt;The CRUD workload confirms this. Native RSS across all frameworks ranges from 31 to 86 MB. JVM containers running the same code: 351-643 MB. The marketing copy is accurate — for CRUD.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Seven Fixes, Zero Errors</title>
      <link>https://tsvinc.dev/posts/seven-fixes-zero-errors/</link>
      <pubDate>Fri, 12 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/seven-fixes-zero-errors/</guid>
      <description>&lt;p&gt;The fix for &amp;ldquo;JVM dies at 256 MB under load&amp;rdquo; was not a JVM flag.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://tsvinc.dev/posts/every-gc-failed-256mb/&#34;&gt;Part 4&lt;/a&gt; ended with Serial GC — the only GC that fits in 256 MB — serving 4,550 requests before the OOM killer showed up. 81% error rate. Same flags, same container, same load profile. Seven code changes later: 1,740,000 requests. Zero errors.&lt;/p&gt;&#xA;&lt;p&gt;No GC tuning. No new JVM flags at all. The problem was never the runtime. It was the code asking the runtime to hold things it didn&amp;rsquo;t need to hold.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Your JVM Reports 151 MB. Your Container Uses 248.</title>
      <link>https://tsvinc.dev/posts/jvm-memory-anatomy/</link>
      <pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/jvm-memory-anatomy/</guid>
      <description>&lt;p&gt;151 MB. That&amp;rsquo;s what micrometer-prometheus reports for the JVM at 256 MB after serving 1.66 million requests. Heap 35 MB, metaspace 72 MB, compressed class space 13 MB, code cache 16 MB, direct buffers 0.75 MB. Add it up. 137 MB. Rounded generously: 151 MB with some measurement timing jitter.&lt;/p&gt;&#xA;&lt;p&gt;Docker stats says 244.2 MiB. Out of 256 MiB. 95.38%.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-visible-budget&#34;&gt;The Visible Budget&lt;/h2&gt;&#xA;&lt;p&gt;After 1.66 million requests, Serial GC, &lt;code&gt;-Xms64m -Xmx64m -Xss256k&lt;/code&gt;, here&amp;rsquo;s what the JVM admits to owning:&lt;/p&gt;</description>
    </item>
    <item>
      <title>107 MB of Invisible JVM RAM</title>
      <link>https://tsvinc.dev/posts/107mb-invisible-jvm-ram/</link>
      <pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/107mb-invisible-jvm-ram/</guid>
      <description>&lt;p&gt;Prometheus says 137 MB. Docker says 244 MiB. &lt;code&gt;/proc/PID/smaps&lt;/code&gt; is the only witness that doesn&amp;rsquo;t lie.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-discrepancy&#34;&gt;The Discrepancy&lt;/h2&gt;&#xA;&lt;p&gt;JVM at 256 MB, Serial GC, after serving 1.66 million requests. Measured at idle:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Docker stats:         244.2 MiB / 256 MiB  (95.38%)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Prometheus reports:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Heap used:           35 MB  (Eden 4.4 + Survivor 0.1 + Tenured 30.5)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Non-heap:           101 MB  (Metaspace 71.9 + CompClass 12.7 + CodeCache 16.3)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Direct buffers:     0.75 MB&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ────────────────────────────&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Total visible:      ~137 MB&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Gap:                  107 MB&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;107 MB that no JMX MBean exposes. No micrometer gauge records it. No Grafana dashboard shows it. To know it exists, you &lt;code&gt;exec&lt;/code&gt; into the container and parse kernel memory maps.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Every GC Failed at 256 MB (Except the Boring One)</title>
      <link>https://tsvinc.dev/posts/every-gc-failed-256mb/</link>
      <pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/every-gc-failed-256mb/</guid>
      <description>&lt;p&gt;Monday: &amp;ldquo;The JVM at 256 MB should work. Just need the right GC.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;Tuesday: G1GC. OOM at 150 concurrent users.&lt;/p&gt;&#xA;&lt;p&gt;Tuesday, later: Shenandoah. OOM at 50 concurrent users.&lt;/p&gt;&#xA;&lt;p&gt;Tuesday, even later: ZGC. OOM at zero concurrent users. Couldn&amp;rsquo;t serve a single request.&lt;/p&gt;&#xA;&lt;p&gt;Wednesday: Serial GC with 7 JVM flags and 3 Micronaut properties. Survives 60 seconds before the OOM killer shows up anyway.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-contenders&#34;&gt;The Contenders&lt;/h2&gt;&#xA;&lt;p&gt;Same app: Micronaut 5.0.0 Space Observatory, 16 REST endpoints, reactive R2DBC, 7-table PostgreSQL schema. Container: 256 MB hard limit, swap disabled. Heap capped at 64 MB (&lt;code&gt;-Xms64m -Xmx64m&lt;/code&gt;). Load: k6, ramping from 10 to 200 concurrent users over 8.5 minutes.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Native Image vs JVM at 128 MB: The Benchmark Nobody Warned Me About</title>
      <link>https://tsvinc.dev/posts/native-vs-jvm-128mb/</link>
      <pubDate>Tue, 26 May 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/native-vs-jvm-128mb/</guid>
      <description>&lt;p&gt;The mental model: native image uses less memory, therefore native image performs better under memory pressure.&lt;/p&gt;&#xA;&lt;p&gt;This is wrong.&lt;/p&gt;&#xA;&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;&#xA;&lt;p&gt;The app: Micronaut 5.0.0 Space Observatory. 4 HTTP clients, reactive R2DBC into PostgreSQL, 7-table schema, 16 REST endpoints. Real enough to matter. (&lt;a href=&#34;https://tsvinc.dev/posts/micronaut-5-native-image/&#34;&gt;Part 1&lt;/a&gt; covers the build.)&lt;/p&gt;&#xA;&lt;p&gt;Four scenarios, clean database each time (&lt;code&gt;docker compose down -v&lt;/code&gt;):&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Native, unlimited memory&lt;/strong&gt; &amp;ndash; baseline&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Native, 128 MB hard limit&lt;/strong&gt; &amp;ndash; &lt;code&gt;mem_limit: 128m&lt;/code&gt;, swap disabled&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;JVM, unlimited memory&lt;/strong&gt; &amp;ndash; same app, &lt;code&gt;java -jar&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;JVM, 128 MB hard limit&lt;/strong&gt; &amp;ndash; same container constraint&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Load: Apache Bench, 1,000 requests x 20 concurrent, container-to-container. DB endpoints only &amp;ndash; no external API calls polluting the numbers. Host: 16 cores, 32 GB RAM, Linux 7.0.9.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
