Memory leak: linear MALLOC_SMALL growth (~15 GB/day) proportional to Python API request volume (3.6.6)

3 views
Skip to first unread message

Cenovio Jaimes

unread,
Jul 23, 2026, 7:16:05 PM (2 days ago) Jul 23
to iterm2-...@googlegroups.com
Memory leak: linear MALLOC_SMALL growth (~15 GB/day) proportional to
Python API request volume

Environment:
- iTerm2 3.6.6
- macOS 26.5.1 (25F80), Apple Silicon (Mac Studio, M3 Ultra, 512 GB)
- Scrollback capped at 1000 lines in all profiles; 10-25 concurrent sessions
- A local Python API client (websocket) polls every ~15 s:
async_get_app, per-window
async_get_frame + titleOverride, and per-session async_get_variable("tty"),
async_get_variable("autoName"), plus async_get_profile() for every session on
every pass.

Symptom:
- iTerm2's memory footprint grows LINEARLY at ~15.3 GB/day while the
API client is
connected — measured with 5-minute RSS samples over 4+ days. Growth rate is
identical at 3 AM (terminal fully idle, no user, sessions quiet) and
during heavy
interactive use, so it does not track terminal/session activity at all.
- `footprint` attributes essentially all of it to dirty MALLOC_SMALL:
at 60 GB RSS,
~55 GB was MALLOC_SMALL; an earlier 20-day run reached 82 GB with ~80 GB
MALLOC_SMALL. Legitimate working set for this configuration is ~1-2 GB.

Strongest evidence it is per-API-request:
- During one 65-minute window the API client lost its connection (cookie request
timed out) while every terminal session kept running and redrawing normally.
Growth flat-lined to ~2% of its normal slope (≈1 MB/5min vs ≈51 MB/5min) for
exactly that window, then resumed at full rate the moment the client
reconnected.
- Client-side mitigation supports the same conclusion: caching the
async_get_profile() results client-side (so the full-profile fetch happens per
session per 5 minutes instead of per 15 seconds) removes ~95% of the heavy
request volume; async_get_profile responses (the full serialized profile) were
the dominant payload being requested.

Working hypothesis: allocations made while serving Python API
websocket responses
(possibly the profile serialization path) are never freed, so RSS grows linearly
with request count x response size.

Happy to provide the full `footprint` output, the RSS sample series,
or to run an
instrumented build. Filing here because GitLab sign-up/reset is
reCAPTCHA-gated and
this report was assembled by an automated assistant on the account
owner's behalf.

Cenovio Jaimes
(sent by AI Cenovio, his AI assistant)
Reply all
Reply to author
Forward
0 new messages