Skip to content

Add threading notes and a persistent worker fetch example - #124

Open
Uyuz-ux wants to merge 1 commit into
treeform:masterfrom
Uyuz-ux:threading-docs
Open

Uyuz-ux wants to merge 1 commit into
treeform:masterfrom
Uyuz-ux:threading-docs

Conversation

@Uyuz-ux

@Uyuz-ux Uyuz-ux commented Nov 5, 2026

Copy link
Copy Markdown

While looking at #123 I reproduced the reported memory growth and traced it. This PR documents what I found and adds a runnable example that avoids the pattern.

What is actually happening (measured on Linux, Nim 2.2.4, ORC default):

  • The exact reproducer from Memory leak when Puppy is used inside a thread #123 grows RSS linearly, ~300 kB per request (24.8 MB at iteration 25 → 47.1 MB at iteration 100, getOccupiedMem() stays 0, matching the report).
  • Puppy itself does not leak per request: running the same fetch loop entirely in the main thread warms up once and then stays flat (23052 kB, +0 over 125 requests).
  • A thread loop that does pure Nim work without importing puppy still grows ~112 kB of RSS per fresh thread — the thread's allocator pages are simply not returned to the OS when a short-lived thread exits under ORC. This is Memory leak with Arc / Orc for allocation inside threads  nim-lang/Nim#23361 (system/threadimpl.nim only calls deallocOsPages() on the old refc path, not on the ARC/ORC path).

This PR

  • README "Threading" section: describes the behavior with the measured numbers, links Memory leak with Arc / Orc for allocation inside threads  nim-lang/Nim#23361, and mentions -d:useMalloc as a workaround for the app itself (it routed allocations through the system allocator; RSS plateaus in my tests, matching the observation in Memory leak when Puppy is used inside a thread #123).
  • examples/threaded_fetch.nim: one long-lived worker thread, jobs/results handed back through Channel (which deep-copies, so the hand-off is safe). Reusing the worker, RSS plateaus after a one-time warm-up and stays flat through 100 requests, while the thread-per-request loop grows ~29 MB over the same 100 requests.

Happy to adjust wording or drop parts of this if the README section is too much — the example is the part I think is most useful for anyone hitting #123.

fetch blocks, so GUI apps often call it from a thread. With one new
thread per request, resident memory grows ~300 kB per request on Linux
(Nim 2.2.4, default ORC): the memory a thread used is not returned to
the OS when the thread exits, see nim-lang/Nim#23361. Puppy itself does
not leak per request: the same fetch loop without any threads is flat.

Documents the pattern and workarounds in the README and adds
examples/threaded_fetch.nim, which reuses one worker thread and hand
results back through channels. Measured with the worker pattern, RSS
plateaus after a one-time warm-up (flat through 100 requests, vs ~29 MB
growth for the thread-per-request loop).

Refs treeform#123

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant