Skip to content

Unbounded memory growth in PersistentJxaSession (v1.34.0) #21

Description

@marc-kang

hey yahor!
really loving the app. it made me aware where i spend my time (the mcp integration is a killer feature). I can't thank more.

but I think I found a osascript bloating on my ram. PersistentJxaSession (introduced in v1.34.0 likely from #20) seems to leak memory unboundedly. the long lived osascript -il JavaScript child grows from ~10 MB to 1.93 GB after ~3 hours and continues climbing. killing the child mid session frees the RAM and the app continues to function.

likely cause (hypothesis)

I think this is consistent with JXA's Obj-C bridge behavior. ObjC.castRefToObject, objectAtIndex, objectForKey produce JS-side wrappers around Obj-C objects that the JSContext doesn't seem to garbage collect over a long-lived process. JXA itself has a long history of bridge GC issues, so reusing one osascript child indefinitely (which v1.34.0 introduced to avoid #20's spawn storm) accumulates wrappers across every 3s poll.

If this read is right, recycling the child on a counter inside PersistentJxaSession would mask it but not fix the underlying behavior. (happy to be wrong on this though, just sharing the suspicion in case it helps narrow it down)

repro

  1. Run Screencap v1.34.0 on macOS. Leave it running with normal browsing for 2–3 hours.
  2. ps -eo pid,ppid,rss,command | grep osascript — find the osascript -il JavaScript whose PPID is the Screencap main process.
  3. Observe RSS growing continuously and unboundedly.
  4. kill Screencap respawns it on the next 3s tick at a small RSS. Memory budget restored. Confirms localization to the JXA process.

measurements

before: PID 84402 (parent: Screencap), RSS 4.43 GB after ~5h uptime
kill the child → Screencap auto-respawns it on the next 3s tick at ~138 MB
the new child's growth, measured every 15s:

  • 5s → 138 MB
  • 40s → 814 MB
  • 55s → 1.15 GB
  • 1:10 → 1.45 GB
  • 1:25 → 1.73 GB
  • 1:38 → 1.95 GB

so ~138 MB → ~1.95 GB in 1m38s. roughly ~57 MB retained per 3s poll under normal use. RSS appears unbounded. I didn't observe asymptote up to ~4.4 GB before killing the original child. killing the JXA child has no observable effect on the app.

happy to run any diagnostics that would help. also no strong opinion on the fix path. I wanted to file the leak first and let you decide direction.

again, thank you for your generous work. it is really changing how i spend my time.

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions