Thanks for the exceptionally well-characterized report. Two steps, in order.
Step 1 — Please try the current 3.7 beta first
We built a load generator that opens a Python-API websocket and fires the exact
async_get_profile request your client sends (get_profile_property_request, all keys),
and hammered it 20,000 times against the latest code:
Settled dirty MALLOC_SMALL before: 54.6 MB → after 20k requests: 43.8 MB (no growth;
it actually ended lower). RSS stayed flat.
At your field rate (~30 KB leaked per request) 20k requests should have added ~600 MB.
We saw none. The request/response, dispatch, websocket, and profile-serialization paths
are clean in the current tree.
So this looks already fixed since 3.6.6. Easiest resolution:
Install the latest 3.7 beta: iTerm2 → Check For Updates (enable beta updates in
Point your API client at it and let it run a few hours.
Watch the footprint. If it stays flat, you're done — it was a bug fixed in a later release.
If it is still leaking on the latest beta, do Step 2 so we can capture the exact stack.
Step 2 — Capture the leaking allocation stack (only if it still leaks)
Important: you need a debuggable build
The signed release build uses the macOS hardened runtime, which blocks the heap-inspection
tools (malloc_history, leaks, vmmap) from attaching — even with sudo. To capture
anything you must run a build signed with get-task-allow.
George will provide a debuggable build of the leaking version (call it iTerm2-debug.app).
Do not use your normal signed copy for this — the tools will just report "not debuggable."
Procedure
Quit iTerm2 completely. Open Terminal and launch the debug build with malloc stack
logging enabled (this must be set at launch):
MallocStackLogging=1 /path/to/iTerm2-debug.app/Contents/MacOS/iTerm2
Leave that Terminal window open — it holds the environment variable for the process.
Let your API client connect and run normally for 30–60 minutes. You do not need a
full day; even a few hundred MB of growth is more than enough to localize it.
Find the process id:
pgrep -x iTerm2
Capture (replace PID with the number from step 3):
malloc_history PID -allBySize > ~/Desktop/mh.txt
leaks PID > ~/Desktop/leaks.txt
vmmap -summary PID > ~/Desktop/vmmap.txt
footprint PID > ~/Desktop/footprint.txt
malloc_history PID -allBySize is the important one: it lists every live allocation
grouped by the call stack that made it, largest total first. The top few stacks point
straight at the leaking code.
Send back mh.txt (the first ~200 lines is plenty), leaks.txt, and vmmap.txt.
Reading the numbers (so the logging overhead doesn't mislead)
MallocStackLogging=1 itself inflates memory a lot and creates large MALLOC_SMALL (empty)
regions. That overhead is expected and is not the leak.
Judge the leak by whether Physical footprint and the dirty column of
MALLOC_SMALL keep climbing over time, and by the top entries of
malloc_history -allBySize.
All of these tools are read-only and safe; they ship with the Xcode Command Line Tools
(xcode-select --install if malloc_history is missing).