<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Lima on Omar Karim Chtioui</title>
    <link>https://blog.okch.pw/tags/lima/</link>
    <description>Recent content in Lima on Omar Karim Chtioui</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 22 May 2026 09:30:00 +0200</lastBuildDate>
    <atom:link href="https://blog.okch.pw/tags/lima/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The RAM that never came back</title>
      <link>https://blog.okch.pw/posts/the-ram-that-never-came-back/</link>
      <pubDate>Fri, 22 May 2026 09:30:00 +0200</pubDate>
      <guid>https://blog.okch.pw/posts/the-ram-that-never-came-back/</guid>
      <description>Colima quietly held onto every gigabyte I ever handed it. Chasing why led me to open a Lima issue — and eventually to OrbStack.</description>
      <content:encoded><![CDATA[<p>I run Docker on my Mac through <a href="https://github.com/abiosoft/colima">Colima</a>,
which sits on top of <a href="https://github.com/lima-vm/lima">Lima</a> and boots a
small Linux VM using Apple&rsquo;s Virtualization.framework (the <code>vz</code> backend).
For a long time it just worked. Then I started noticing my Mac getting
slower the longer my workday went on — and the cause turned out to be a bug
worth writing down.</p>
<h2 id="the-symptom">The symptom</h2>
<p>Build a few images, run a memory-hungry container, do some real work. At
some point the VM touches the memory ceiling I configured for it. Fine —
that&rsquo;s what the ceiling is for.</p>
<p>The problem is what happens <em>after</em>. The containers exit, the build
finishes, the guest goes quiet — and the host process backing the VM stays
pinned at that peak. In Activity Monitor it shows up as a process holding
several gigabytes of RAM with nothing running inside it. It never comes
back down. The only thing that frees the memory is restarting the VM.</p>
<p>So my &ldquo;8 GB Docker VM&rdquo; wasn&rsquo;t an 8 GB <em>budget</em>. It was an 8 GB <em>high-water
mark</em>, and once I hit it, those 8 GB were gone from the rest of the system
until I remembered to bounce Colima.</p>
<h2 id="what-i-expected">What I expected</h2>
<p>A fresh VM idles at maybe 800 MB–1 GB. My mental model was simple: memory
usage should track what the guest is actually doing. Spike under load,
settle back down when idle. That&rsquo;s how a process is supposed to behave, and
it&rsquo;s how the VM&rsquo;s <em>guest</em> behaves — Linux inside the VM frees the pages
just fine.</p>
<p>The host side is what doesn&rsquo;t let go.</p>
<h2 id="opening-the-issue">Opening the issue</h2>
<p>I went looking and found I wasn&rsquo;t the first to hit this — there was already
a discussion describing the exact behavior I was seeing. It matched closely
enough that I opened a tracking issue on Lima to get it properly on the
radar:</p>
<blockquote>
<p><a href="https://github.com/lima-vm/lima/issues/2789"><strong>lima-vm/lima#2789</strong> — Memory is not being freed on VZ</a></p>
</blockquote>
<p>What I learned from the thread is the interesting part.</p>
<h2 id="why-it-happens">Why it happens</h2>
<p>The first answer from a maintainer reframed it for me: memory you
<em>dedicate</em> to a virtual machine being locked is, in a sense, normal. A VM
isn&rsquo;t an ordinary process; the host commits that memory to it. The
mechanism that would let it shrink back has a name —
<a href="https://en.wikipedia.org/wiki/Memory_ballooning">memory ballooning</a> — and
it isn&rsquo;t on by default.</p>
<p>The next answer was blunter, and the one that actually explained my Mac:
this is a <strong>macOS bug</strong>. It&rsquo;s not specific to Lima or Colima. Docker
Desktop exhibits the same thing, because they all sit on the same Apple
framework. The one tool that <em>doesn&rsquo;t</em> — <a href="https://orbstack.dev/">OrbStack</a> —
got there by building its own dynamic memory management.</p>
<p>OrbStack did write a <a href="https://orbstack.dev/blog/dynamic-memory">blog post about it</a>,
and it&rsquo;s worth reading — but notice what it doesn&rsquo;t say. It explains <em>that</em>
the VM&rsquo;s footprint grows and shrinks on demand, and why that matters; it
doesn&rsquo;t really explain <em>how</em> they pulled it off on the very same Apple
framework that leaves everyone else stuck. The post is about the result,
not the recipe. Whatever they&rsquo;re doing, they&rsquo;re keeping it to themselves —
which is fair, but it means the rest of the ecosystem can&rsquo;t just copy it.</p>
<h2 id="the-balloon-that-wont-deflate">The balloon that won&rsquo;t deflate</h2>
<p>Apple&rsquo;s framework <em>does</em> expose a balloon device
(<code>VZVirtioTraditionalMemoryBalloonDevice</code>), and Lima even creates one. In
theory you shrink the VM&rsquo;s footprint by lowering its
<code>targetVirtualMachineMemorySize</code> while it runs: the guest hands unused
pages back, the host reclaims them.</p>
<p>In practice, on the <code>vz</code> backend, it doesn&rsquo;t reclaim anything. My short
contribution to the thread was exactly that observation — the device is
<em>available</em>, it just doesn&rsquo;t <em>work</em>.</p>
<p>That&rsquo;s not me guessing anymore. Over a year later, someone posted an
instrumented test on macOS 26: a tiny VM, a controlled allocation, host RSS
sampled once a second. The guest cooperates fully and frees its memory; the
host process&rsquo;s memory footprint is <strong>monotonic across the whole run — it
never decreases</strong>. They&rsquo;ve since filed an Apple Feedback report. The issue
is still open.</p>
<h2 id="where-i-landed">Where I landed</h2>
<p>Knowing the root cause didn&rsquo;t fix my Mac. The realistic options were:</p>
<ul>
<li><strong>Restart the VM periodically</strong> to reclaim memory — a chore, and easy to
forget until the machine is already crawling.</li>
<li><strong>Cap the VM&rsquo;s memory low enough</strong> that the locked amount doesn&rsquo;t hurt —
which just trades one problem for another, since now heavy builds are
starved.</li>
<li><strong>Use the tool that solved it.</strong></li>
</ul>
<p>I switched to OrbStack. Its dynamic memory management is the entire feature
I was missing: the footprint expands under load and <em>actually contracts</em>
when the work is done. For the way I use containers on a laptop, that&rsquo;s not
a nice-to-have — it&rsquo;s the whole point.</p>
<h2 id="takeaways">Takeaways</h2>
<ol>
<li><strong>&ldquo;Locked&rdquo; and &ldquo;leaked&rdquo; look identical in Activity Monitor.</strong> A VM
holding its peak forever isn&rsquo;t leaking; it&rsquo;s a platform that never
reclaims. Same symptom, different cause — and the fix is different too.</li>
<li><strong>A feature existing in the SDK doesn&rsquo;t mean it works.</strong> Lima creates
the balloon device; the balloon still doesn&rsquo;t deflate. &ldquo;Available&rdquo; is
not &ldquo;functional.&rdquo;</li>
<li><strong>It&rsquo;s worth filing the issue even when it&rsquo;s not the project&rsquo;s fault.</strong>
#2789 isn&rsquo;t a Lima bug, strictly — but having a public, linkable thread
is how the next person finds the explanation in twenty minutes instead
of a week.</li>
</ol>
<p>The RAM still doesn&rsquo;t come back on <code>vz</code>. But at least now I know why — and
I&rsquo;m running something that doesn&rsquo;t need it to.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
