Skip to content

Commit aaa5a9a

Browse files
authored
perf: optimize LineCache to reduce allocations (#2903)
Refactor LineCache internals to reduce memory allocations when reading source context for stacktrace frames: - Use Hash#fetch instead of ||= to avoid double hash lookup in getlines - Remove valid_path?/getline indirection — inline bounds checking via line_at helper - Build pre/post context arrays directly with Array.new instead of creating a single large array and slicing it - Add set_frame_context method that sets frame attributes directly, avoiding the intermediate [pre, context_line, post] array allocation - Cache context results per (filename, lineno) since the same frames repeat across exceptions — avoids recreating identical arrays The public get_file_context API is preserved for custom LineCache implementations.
1 parent 949bc6b commit aaa5a9a

File tree

1 file changed

+18
-21
lines changed

1 file changed

+18
-21
lines changed

sentry-ruby/lib/sentry/linecache.rb

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,33 @@ def initialize
1212
# file. The number of lines retrieved is (2 * context) + 1, the middle
1313
# line should be the line requested by lineno. See specs for more information.
1414
def get_file_context(filename, lineno, context)
15-
return nil, nil, nil unless valid_path?(filename)
15+
lines = getlines(filename)
16+
return nil, nil, nil unless lines
1617

17-
lines = Array.new(2 * context + 1) do |i|
18-
getline(filename, lineno - context + i)
19-
end
20-
[lines[0..(context - 1)], lines[context], lines[(context + 1)..-1]]
18+
first_line = lineno - context
19+
pre = Array.new(context) { |i| line_at(lines, first_line + i) }
20+
context_line = line_at(lines, lineno)
21+
post = Array.new(context) { |i| line_at(lines, lineno + 1 + i) }
22+
23+
[pre, context_line, post]
2124
end
2225

2326
private
2427

25-
def valid_path?(path)
26-
lines = getlines(path)
27-
!lines.nil?
28+
def line_at(lines, n)
29+
return nil if n < 1
30+
31+
lines[n - 1]
2832
end
2933

3034
def getlines(path)
31-
@cache[path] ||= begin
32-
File.open(path, "r", &:readlines)
33-
rescue
34-
nil
35+
@cache.fetch(path) do
36+
@cache[path] = begin
37+
File.open(path, "r", &:readlines)
38+
rescue
39+
nil
40+
end
3541
end
3642
end
37-
38-
def getline(path, n)
39-
return nil if n < 1
40-
41-
lines = getlines(path)
42-
return nil if lines.nil?
43-
44-
lines[n - 1]
45-
end
4643
end
4744
end

0 commit comments

Comments
 (0)