perf: use shallow dup instead of deep_dup for Scope and BreadcrumbBuffer#2907
Closed
perf: use shallow dup instead of deep_dup for Scope and BreadcrumbBuffer#2907
Conversation
⚠️ Needs closer review — changes copy semantics for scope containers. Replace deep_dup with dup for Scope's contexts, extra, tags, user, and fingerprint hashes, and for BreadcrumbBuffer's buffer array. Rationale: These containers are not mutated in-place after duplication. Scope methods like set_tags, set_extras, set_user all use assignment (replacing the entire hash) or merge! on the copy's own hash. The inner values (strings, numbers, symbols) are immutable or treated as such. BreadcrumbBuffer: Individual Breadcrumb objects in the buffer are not mutated after being recorded — they are only read during serialization. A shallow dup of the buffer array is sufficient to prevent the copy from seeing new breadcrumbs added to the original. span, session, and propagation_context still use deep_dup as they contain mutable nested state that may be modified in-place.
HazAT
added a commit
that referenced
this pull request
Mar 18, 2026
Reduce total allocated memory from 442k to 206k bytes (-53.5%) and
objects from 3305 to 1538 (-53.5%) per Rails exception capture.
All changes are internal optimizations with zero behavior changes.
Key optimizations:
- Cache longest_load_path and compute_filename results (class-level,
invalidated on $LOAD_PATH changes)
- Cache backtrace line parsing and Line/Frame object creation (bounded
at 2048 entries)
- Optimize LineCache with Hash#fetch, direct context setting, and
per-(filename, lineno) caching
- Avoid unnecessary allocations: indexed regex captures, match? instead
of =~, byteslice, single-pass iteration in StacktraceBuilder
- RequestInterface: avoid env.dup, cache header name transforms, ASCII
fast-path for encoding
- Scope/BreadcrumbBuffer: shallow dup instead of deep_dup where inner
values are not mutated after duplication
- Hub#add_breadcrumb: hint default nil instead of {} to avoid empty
hash allocation
See sub-PRs for detailed review by risk level:
- #2902 (low risk) — hot path allocation avoidance
- #2903 (low risk) — LineCache optimization
- #2904 (medium risk) — load path and filename caching
- #2905 (needs review) — backtrace parse caching
- #2906 (needs review) — Frame object caching
- #2907 (needs review) — Scope/BreadcrumbBuffer shallow dup
- #2908 (medium risk) — RequestInterface optimizations
Member
|
don't want to risk this and the % change in allocation is not that high. |
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.
Part of #2901 (reduce memory allocations by ~53%)
Changes
Replace
deep_dupwithdupfor:contexts,extra,tags,user,fingerprintbufferarrayRationale
Scope: These containers are not mutated in-place after duplication. Scope methods like
set_tags,set_extras,set_userall use assignment (replacing the entire hash) ormerge!on the copy's own hash. The inner values (strings, numbers, symbols) are immutable or treated as such.BreadcrumbBuffer: Individual
Breadcrumbobjects in the buffer are not mutated after being recorded — they are only read during serialization. A shallowdupof the buffer array is sufficient to prevent the copy from seeing new breadcrumbs added to the original.span,session, andpropagation_contextstill usedeep_dupas they contain mutable nested state that may be modified in-place.Review focus
contexts/extra/tags/userare mutated in-place (rather than replaced)?