From 8b735a7df8fadf2f0c0abb12b90ff70fa1426cb1 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 18 Mar 2026 15:55:30 +0100 Subject: [PATCH] perf: cache Frame objects in StacktraceBuilder by Line identity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠️ Needs closer review — caches Frame objects by Line object_id. When combined with Line object caching (where identical backtrace lines return the same Line instance), this cache avoids recreating Frame objects for the same source locations across exceptions. The cache key is Line#object_id, which is stable for cached Line objects. For non-cached Lines, unique object_ids mean no false cache hits. Cache is per-StacktraceBuilder instance (not class-level), bounded to 2048 entries. Frame objects are effectively read-only after context is set — attributes are only read during to_h serialization. This is most effective when paired with the Line object caching PR, but provides modest benefit independently (avoids Frame recreation within a single exception's backtrace when duplicate frames exist). --- sentry-ruby/lib/sentry/interfaces/stacktrace_builder.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sentry-ruby/lib/sentry/interfaces/stacktrace_builder.rb b/sentry-ruby/lib/sentry/interfaces/stacktrace_builder.rb index 3f4a7f090..4590269d8 100644 --- a/sentry-ruby/lib/sentry/interfaces/stacktrace_builder.rb +++ b/sentry-ruby/lib/sentry/interfaces/stacktrace_builder.rb @@ -78,8 +78,16 @@ def build(backtrace:, &frame_callback) private def convert_parsed_line_into_frame(line) + # Cache frames by Line object identity — same Line produces same Frame + cache_key = line.object_id + cached_frame = @frame_cache&.[](cache_key) + return cached_frame if cached_frame + frame = StacktraceInterface::Frame.new(project_root, line, strip_backtrace_load_path) frame.set_context(linecache, context_lines) if context_lines + + @frame_cache ||= {} + @frame_cache[cache_key] = frame if @frame_cache.size < 2048 frame end