-
Notifications
You must be signed in to change notification settings - Fork 4.6k
transport: Reduce heap allocations #8668
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
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8668 +/- ##
==========================================
+ Coverage 81.97% 83.17% +1.20%
==========================================
Files 417 417
Lines 40788 32178 -8610
==========================================
- Hits 33435 26764 -6671
+ Misses 5991 4034 -1957
- Partials 1362 1380 +18
🚀 New features to boost your workflow:
|
| closeStream: func(err error) { | ||
| s.Close(err) | ||
| }, |
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.
What heap allocation does this reduce?
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.
The closeStream closure captures a variable, s, from outside its own body.
The Go compiler performs escape analysis to determine if a variable can safely live on the stack or if it must be "escaped" to the heap. A variable on the stack is automatically freed when its parent function returns. The closeStream function might be called long after the function that created it has returned (for example, if it's stored in a struct field that lives on).
If s remained on the stack of the creating function, the closeStream function would be left holding an invalid pointer to garbage memory. To prevent this, the compiler sees that s is captured by a closure that might outlive the current function. It therefore allocates s on the heap instead of the stack. The closure then holds a valid pointer to this heap-allocated s.
Note that even though s already points to data on the heap, the s variable itself (the pointer) also escapes. This is different from simply assigning s to a struct field. In that case, a copy of the pointer s is stored in the field. With a closure, the closure captures a reference to the original s variable, forcing that variable to move to the heap so it can be safely shared.
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.
Cool. That helps. The last paragraph was what I wanted. Because I was thinking the ClientStream should already be on the heap, so what is this change preventing. Thanks.
| closeStream: func(err error) { | ||
| s.Close(err) | ||
| }, |
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.
Cool. That helps. The last paragraph was what I wanted. Because I was thinking the ClientStream should already be on the heap, so what is this change preventing. Thanks.
Benchmarks
RELEASE NOTES: N/A