Repository navigation
builder: copy pack bytes into blocks as they arrive, not keep the network chunks - #14
Merged
Merged
Conversation
…work chunks The receive loop kept every network chunk until a pack was whole: tens of thousands of 16-64 KB allocations, freed together at the end among allocations that live on, a heap glibc cannot give back. It is part of why a production instance sat at 1,171 MB resident with 22 MB live after google/site-kit-wp and google/filament were refused as too big. Pack bytes are now copied out of each chunk into blocks that double from 64 KB to 64 MB, joined once at the end, and the chunk goes as soon as it is read. The pkt-line parser keeps its place across chunks instead of joining them, so a length, side band or text line split anywhere still parses. Replayed locally from the same recorded GitHub responses, one repo after another in one process as a warm instance runs them, each turn opened with the last-resort collection (peak / after, MB): google/site-kit-wp (too big) 781 / 436 on main 705 / 364 here google/dawn 1,129 / 467 1,021 / 371 anomalyco/opencode 1,082 / 480 994 / 372 The records are byte for byte the same on main and here, and the times are the same.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
azank1
marked this pull request as ready for review
October 13, 2026 16:54
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After #13, every buildable repo builds, but instances keep memory they no longer use. After google/site-kit-wp and google/filament were refused as too big, a production instance logged 22 MB live and 1,171 MB resident, even after V8's last-resort collection. Resident memory is what the busy check and the platform's out-of-memory kill go by. anomalyco/opencode needed one busy retry in the rebuild.
What this changes
The receive loop kept every network chunk until a pack was whole. That's tens of thousands of 16–64 KB allocations, freed together at the end among allocations that live on, which leaves a heap glibc can't give back. Pack bytes now go from each chunk into blocks that double from 64 KB to 64 MB, joined once at the end. Each chunk is dropped as soon as it's read. The pkt-line parser keeps its place across chunks instead of joining them, so a length, side band or text line split anywhere still parses.
Measured on real responses
I recorded GitHub's responses once, then replayed them from disk through main and through this branch. The repos ran one after another in one process, as a warm instance runs them, each turn opened with the last-resort collection, on Node 22.
e56157187d4b3706, opencode3b24937b68fd684e(SHA-1 of the record JSON). site-kit-wp stops at the same point in both.#13 dropped a block rewrite because its peak measured the same. Peak was the wrong measure, and that benchmark also kept each round's result in scope, which hid the difference.
Proposed, not applied:
MALLOC_MMAP_THRESHOLD_=131072Most of what's still resident is glibc's main heap, at about 286 MB. glibc raises its mmap threshold each time it frees a mapped block, up to 32 MB. After that, blocks and 1 MB tree slabs land in the heap too. Setting the threshold pins it at 128 KB and turns that adjustment off. Same recordings:
On main the setting barely helps, because kept chunks are under 128 KB. With this branch, what stays resident drops by more than half, and peaks drop by 230–300 MB on dawn and opencode. It's a project environment variable that glibc reads at process start, so it needs azank's go. It's not part of this PR.
Tests
LIVE=1: all 5 pass on this branch. They download over HTTPS and check every commit against a full clone.After deploy: read the
big replay's turn after … collected: … rss X -> Y MBlog line on the next big rebuild.