Class: DeadBro::LightweightMemoryTracker
- Inherits:
-
Object
- Object
- DeadBro::LightweightMemoryTracker
- Defined in:
- lib/dead_bro/lightweight_memory_tracker.rb
Constant Summary collapse
- THREAD_LOCAL_KEY =
Ultra-lightweight memory tracking with minimal performance impact
:dead_bro_lightweight_memory
Class Method Summary collapse
- .lightweight_gc_stats ⇒ Object
- .lightweight_memory_usage ⇒ Object
- .start_request_tracking ⇒ Object
- .stop_request_tracking ⇒ Object
Class Method Details
.lightweight_gc_stats ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/dead_bro/lightweight_memory_tracker.rb', line 55 def self.lightweight_gc_stats return {} unless defined?(GC) && GC.respond_to?(:stat) stats = GC.stat { count: stats[:count] || 0, heap_allocated_pages: stats[:heap_allocated_pages] || 0 } rescue {} end |
.lightweight_memory_usage ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/dead_bro/lightweight_memory_tracker.rb', line 45 def self.lightweight_memory_usage # Real RSS, cached for ~1s across threads so this is cheap even on hot # paths. Previous versions multiplied heap_pages by 4KB and labelled the # result as MB — both the unit and the page size were wrong (MRI heap # pages are ~16KB and heap != RSS), so the number was effectively fiction. DeadBro::MemoryHelpers.rss_mb rescue 0 end |
.start_request_tracking ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/dead_bro/lightweight_memory_tracker.rb', line 8 def self.start_request_tracking return unless DeadBro.configuration.memory_tracking_enabled # Stack allows nested job tracking (e.g. one job performing others in the same thread) mem_before = lightweight_memory_usage frame = { gc_before: lightweight_gc_stats, memory_before: mem_before, start_time: Process.clock_gettime(Process::CLOCK_MONOTONIC) } (Thread.current[THREAD_LOCAL_KEY] ||= []) << frame end |
.stop_request_tracking ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/dead_bro/lightweight_memory_tracker.rb', line 21 def self.stop_request_tracking stack = Thread.current[THREAD_LOCAL_KEY] unless stack.is_a?(Array) && stack.any? Thread.current[THREAD_LOCAL_KEY] = nil return {} end events = stack.pop Thread.current[THREAD_LOCAL_KEY] = nil if stack.empty? # Calculate only essential metrics gc_after = lightweight_gc_stats memory_after = lightweight_memory_usage { memory_growth_mb: (memory_after - events[:memory_before]).round(2), gc_count_increase: (gc_after[:count] || 0) - (events[:gc_before][:count] || 0), heap_pages_increase: (gc_after[:heap_allocated_pages] || 0) - (events[:gc_before][:heap_allocated_pages] || 0), duration_seconds: Process.clock_gettime(Process::CLOCK_MONOTONIC) - events[:start_time], memory_before: events[:memory_before], memory_after: memory_after } end |