Skip to content

transport: avoid allocation when releasing shared write buffers#9233

Open
zaidoon1 wants to merge 1 commit into
grpc:masterfrom
zaidoon1:transport-reuse-shared-write-buffer-handle
Open

transport: avoid allocation when releasing shared write buffers#9233
zaidoon1 wants to merge 1 commit into
grpc:masterfrom
zaidoon1:transport-reuse-shared-write-buffer-handle

Conversation

@zaidoon1

@zaidoon1 zaidoon1 commented Jul 15, 2026

Copy link
Copy Markdown

Shared write buffers currently add one heap allocation whenever bufWriter returns a buffer to the pool. This PR removes that allocation. It does not change when buffers are shared or released, and it does not change Go's GC pacing.

After upgrading a service with many long lived gRPC connections and streaming responses, we saw more time spent in garbage collection. The investigation found two separate effects:

  1. Shared write buffers reduce retained heap, which can cause Go to collect more frequently depending on the application's GC settings.
  2. bufWriter.Flush copies the buffer's slice header into a local variable and passes its address to the pool. That local variable escapes to the heap, adding one 24-byte allocation to every write and flush cycle.

This PR only fixes the second issue.

The writer now keeps the pointer returned by the pool while the buffer is in use and returns that same pointer after flushing. It also releases the buffer when a network write fails before the normal Flush path.

The benchmark added in this change can be run with:

go test ./internal/transport -run '^$' -bench '^BenchmarkBufWriter/Shared/WriteAndFlush$' -benchmem -count=10

Results on an Apple M4 Pro with Go 1.26.5:

before: 24.2-26.2 ns/op, 24 B/op, 1 alloc/op
after:  13.5-13.9 ns/op,  0 B/op, 0 alloc/op

Tests run:

go test -cpu 1,4 -timeout 7m ./internal/transport
go test -race -cpu 1,4 -timeout 7m ./internal/transport

RELEASE NOTES:

  • transport: Avoid an allocation when returning a shared write buffer to the pool.

Shared write buffers currently copy the slice header into a local variable and pass its address to the pool on every flush. The local escapes to the heap, adding one allocation to each write and flush cycle.

Keep the pointer returned by the pool while the buffer is in use and return that same pointer after flushing. Also release it when a network write fails before the normal Flush path.
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 15, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: zaidoon1 / name: Zaidoon Abd Al Hadi (6a1d191)

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.23%. Comparing base (f8a85fa) to head (6a1d191).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9233      +/-   ##
==========================================
- Coverage   83.30%   83.23%   -0.08%     
==========================================
  Files         421      421              
  Lines       34061    34066       +5     
==========================================
- Hits        28375    28354      -21     
- Misses       4261     4275      +14     
- Partials     1425     1437      +12     
Files with missing lines Coverage Δ
internal/transport/http_util.go 96.64% <100.00%> (+0.05%) ⬆️

... and 20 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@easwars easwars self-assigned this Jul 16, 2026
@easwars easwars added the Type: Performance Performance improvements (CPU, network, memory, etc) label Jul 16, 2026
@easwars easwars added this to the 1.84 Release milestone Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Performance Performance improvements (CPU, network, memory, etc)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants