<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Memory on tsvinc</title>
    <link>https://tsvinc.dev/tags/memory/</link>
    <description>Recent content in Memory on tsvinc</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 05 Jul 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://tsvinc.dev/tags/memory/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Six OOMs and a Connection Pool</title>
      <link>https://tsvinc.dev/posts/six-ooms-one-http-client/</link>
      <pubDate>Sun, 05 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/six-ooms-one-http-client/</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 23 of &lt;a href=&#34;https://tsvinc.dev/series/micronaut-256mb/&#34;&gt;the Micronaut native image series&lt;/a&gt;. Follows &lt;a href=&#34;https://tsvinc.dev/posts/three-front-doors-one-engine/&#34;&gt;Part 22&lt;/a&gt;, where the reactive ports reached throughput parity across three frameworks. Assumes familiarity with Spring&amp;rsquo;s RestClient and GraalVM native image.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;The same 28-API fan-out app runs comfortably at 256 MB on Quarkus. Runs comfortably on Micronaut. On the imperative Spring Boot 4.1 port &amp;ndash; Spring MVC, virtual threads, JdbcClient &amp;ndash; it OOM&amp;rsquo;d. Then I fixed it and it OOM&amp;rsquo;d differently. Six benchmark runs. Six different failure modes. Each one peeling back a layer of what &amp;ldquo;choosing an HTTP client&amp;rdquo; actually means in a memory-constrained native image.&lt;/p&gt;</description>
    </item>
    <item>
      <title>-Xmx Won&#39;t Save Your Native Image</title>
      <link>https://tsvinc.dev/posts/xmx-wont-save-native-image/</link>
      <pubDate>Fri, 03 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://tsvinc.dev/posts/xmx-wont-save-native-image/</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 19 of &lt;a href=&#34;https://tsvinc.dev/series/micronaut-256mb/&#34;&gt;the Micronaut native image series&lt;/a&gt;. Follows &lt;a href=&#34;https://tsvinc.dev/posts/counter-reset-benchmark-lied/&#34;&gt;Part 18&lt;/a&gt;, where a reset Prometheus counter made the benchmark lie. Assumes familiarity with GraalVM native image and Docker memory limits.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-confident-wrong-fix&#34;&gt;The Confident Wrong Fix&lt;/h2&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-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# docker-compose.yml — the JVM reflex&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;JAVA_TOOL_OPTIONS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;-Xmx128m&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Standard. Reliable. Every JVM deployment in every Kubernetes cluster in the world does this. It has never not worked.&lt;/p&gt;&#xA;&lt;p&gt;It is a no-op on a native binary.&lt;/p&gt;&#xA;&lt;p&gt;GraalVM native images are not JVMs. They don&amp;rsquo;t read &lt;code&gt;JAVA_TOOL_OPTIONS&lt;/code&gt;. They don&amp;rsquo;t read &lt;code&gt;-Xmx&lt;/code&gt; from environment variables. &lt;a href=&#34;https://github.com/oracle/graal/issues/4650&#34;&gt;GraalVM issue #4650&lt;/a&gt; requested this capability. &lt;a href=&#34;https://github.com/oracle/graal/issues/9504&#34;&gt;Issue #9504&lt;/a&gt; confirmed it&amp;rsquo;s still not supported. Your heap cap does nothing. No warning. No error. The binary starts, ignores the variable, sizes its heap however it wants.&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>
  </channel>
</rss>
