-
Notifications
You must be signed in to change notification settings - Fork 42
fix(httputil): optimize ResponseChain memory usage
#700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Mzack9999
merged 5 commits into
main
from
dwisiswant0/fix/httputil/optimize-ResponseChain-memory-usage-to-prevent-OOM
Nov 18, 2025
Merged
fix(httputil): optimize ResponseChain memory usage
#700
Mzack9999
merged 5 commits into
main
from
dwisiswant0/fix/httputil/optimize-ResponseChain-memory-usage-to-prevent-OOM
Nov 18, 2025
Conversation
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
Member
Author
|
Wait. |
606f237 to
147a6f2
Compare
Member
Author
|
Rebase after #701. |
Signed-off-by: Dwi Siswanto <[email protected]>
to prevent OOM. `ResponseChain` currently suffers from unbounded memory growth under high-concurrency workloads, particularly when processing large responses or compression bombs. This manifests as OOM kills during nuclei scans with many concurrent requests. The root cause is threefold: `(*bytes.Buffer).ReadFrom()` over-allocates by doubling capacity when size is unknown, the buffer pool accumulates large buffers w/o bounds, and each `ResponseChain` pre-allocates a `fullResponse` buffer, even when unused. Introduce `limitedBuffer` wrapper to constrain buffer growth. This wrapper uses 32KB chunks and caps total capacity at `maxBodyRead`, preventing the 2x over-allocation behavior of `(*bytes.Buffer).ReadFrom()`. Reading now grows incrementally rather than speculatively. Implement semaphore-gated pooling for large buffers. Buffers under 512KB are pooled freely as most HTML responses fall in this range. Buffers at or above 512KB are limited to 20 pooled instances via semaphore. When the limit is reached, excess large buffers are discarded and reclaimed by GC. This prevents pool pollution from transient large responses while still enabling reuse during burst periods. Remove the pre-allocated `fullResponse` buffer from `ResponseChain` struct. Generate it lazily only when `FullResponse()` is called. This reduces per-instance memory footprint by one-third and eliminates waste when callers only need headers or body separately. Add runtime configuration via `SetMaxBodySize()`, `SetBufferSize()`, and `SetMaxLargeBuffers()` to allow tuning based on deployment characteristics. Increase default max body size from 4MB to 8MB to accommodate modern web apps. Also remove dependency on docker/go-units. Provide typed accessor methods `HeadersBytes()`, `HeadersString()`, `BodyBytes()`, `BodyString()`, and `FullResponseString()` for safe read-only access. These prevent callers from inadvertently retaining pooled buffers beyond their lifecycle. The `FullResponse()` method now returns a buffer that must be explicitly managed by the caller. This is a breaking change but necessary to support lazy generation semantics. Testing with nuclei workloads shows stable memory usage under sustained load where previously OOM would occur within minutes. ```bash go test -v -run "(BurstW(ithPoolExhaustion|orkload)|SustainedConcurrency|RapidCreateDestroy|ConcurrentReads|M(emoryPressure|ixedWorkload))$" -count 1 ./http/ ``` Signed-off-by: Dwi Siswanto <[email protected]>
Signed-off-by: Dwi Siswanto <[email protected]>
Signed-off-by: Dwi Siswanto <[email protected]>
Signed-off-by: Dwi Siswanto <[email protected]>
147a6f2 to
d06a121
Compare
Member
Author
Yep! It's all green now. Ready to review. :) |
Mzack9999
approved these changes
Nov 18, 2025
Member
Mzack9999
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Type: Optimization
Increasing the performance/optimization. Not an issue, just something to consider.
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.

This PR fixes #699; a memory leak in
ResponseChainthat causes 2.9 GB memory retention during burst workloads, leading to OOM crashes in production Nuclei scans. The optimization reduces memory usage by 64-99% while improving performance by 38-57%.Proposed Changes
API Changes
Deprecated (but maintained for compat):
New config funcs:
No breaking changes at all. All existing APIs are maintained for backward compatibility.
Migration Guide
No migration needed. Existing code works w/o changes. BUT:
Switching to the new safe accessors is highly recommended for better perf:
Proof
patch:
main:
comparison:
main. Patch still does a lot of allocs (TotalAlloclarge) but does NOT retain them; memory is reclaimed.