Module: DeadBro::MemoryHelpers
- Defined in:
- lib/dead_bro/memory_helpers.rb
Constant Summary collapse
- RSS_CACHE_TTL_SECONDS =
Helper methods for memory tracking and leak detection
1.0
Class Method Summary collapse
-
.analyze_memory ⇒ Object
Get current memory analysis.
-
.check_for_leaks ⇒ Object
Check for memory leaks.
-
.clear_history ⇒ Object
Clear memory history (useful for testing).
-
.memory_summary ⇒ Object
Get memory usage summary.
-
.monitor_memory(label, &block) ⇒ Object
Monitor memory during a block execution.
- .read_rss_bytes ⇒ Object
- .read_rss_from_proc_status ⇒ Object
- .read_rss_from_ps ⇒ Object
-
.rss_bytes ⇒ Object
Current process RSS in bytes.
- .rss_mb ⇒ Object
-
.snapshot(label) ⇒ Object
Take a memory snapshot with a custom label.
-
.top_allocators ⇒ Object
Get top memory allocating classes.
Class Method Details
.analyze_memory ⇒ Object
Get current memory analysis
75 76 77 |
# File 'lib/dead_bro/memory_helpers.rb', line 75 def self.analyze_memory DeadBro::MemoryLeakDetector.get_memory_analysis end |
.check_for_leaks ⇒ Object
Check for memory leaks
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/dead_bro/memory_helpers.rb', line 80 def self.check_for_leaks analysis = analyze_memory if analysis[:leak_alerts]&.any? puts "🚨 Memory leak detected!" analysis[:leak_alerts].each do |alert| puts " - Growth: #{alert[:memory_growth_mb]}MB" puts " - Rate: #{alert[:growth_rate_mb_per_second]}MB/sec" puts " - Confidence: #{(alert[:confidence] * 100).round(1)}%" puts " - Recent controllers: #{alert[:recent_controllers].join(", ")}" end else puts "✅ No memory leaks detected" end analysis end |
.clear_history ⇒ Object
Clear memory history (useful for testing)
137 138 139 |
# File 'lib/dead_bro/memory_helpers.rb', line 137 def self.clear_history DeadBro::MemoryLeakDetector.clear_history end |
.memory_summary ⇒ Object
Get memory usage summary
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/dead_bro/memory_helpers.rb', line 97 def self.memory_summary analysis = analyze_memory return "Insufficient data" if analysis[:status] == "insufficient_data" memory_stats = analysis[:memory_stats] puts "📊 Memory Summary:" puts " - Current: #{memory_stats[:mean]}MB (avg)" puts " - Range: #{memory_stats[:min]}MB - #{memory_stats[:max]}MB" puts " - Volatility: #{memory_stats[:std_dev]}MB" puts " - Samples: #{analysis[:sample_count]}" if analysis[:memory_trend][:slope] > 0 puts " - Trend: ↗️ Growing at #{analysis[:memory_trend][:slope].round(3)}MB/sec" elsif analysis[:memory_trend][:slope] < 0 puts " - Trend: ↘️ Shrinking at #{analysis[:memory_trend][:slope].abs.round(3)}MB/sec" else puts " - Trend: ➡️ Stable" end analysis end |
.monitor_memory(label, &block) ⇒ Object
Monitor memory during a block execution
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/dead_bro/memory_helpers.rb', line 120 def self.monitor_memory(label, &block) snapshot("before_#{label}") result = yield snapshot("after_#{label}") # Get the difference analysis = analyze_memory if analysis[:memory_stats] puts "🔍 Memory monitoring for '#{label}':" puts " - Memory change: #{analysis[:memory_stats][:max] - analysis[:memory_stats][:min]}MB" puts " - Peak usage: #{analysis[:memory_stats][:max]}MB" end result end |
.read_rss_bytes ⇒ Object
40 41 42 43 44 45 46 47 48 |
# File 'lib/dead_bro/memory_helpers.rb', line 40 def self.read_rss_bytes if File.readable?("/proc/self/status") read_rss_from_proc_status else read_rss_from_ps end rescue 0 end |
.read_rss_from_proc_status ⇒ Object
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/dead_bro/memory_helpers.rb', line 50 def self.read_rss_from_proc_status File.foreach("/proc/self/status") do |line| next unless line.start_with?("VmRSS:") kb = line.split[1].to_i return kb * 1024 if kb > 0 end 0 rescue 0 end |
.read_rss_from_ps ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/dead_bro/memory_helpers.rb', line 61 def self.read_rss_from_ps kb = `ps -o rss= -p #{Process.pid}`.to_i return 0 if kb <= 0 kb * 1024 rescue 0 end |
.rss_bytes ⇒ Object
Current process RSS in bytes. Uses /proc/self/status on Linux (cheap read) and falls back to ‘ps` elsewhere. Result is cached for 1s across threads so this is safe to call from every request without flooding the kernel.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/dead_bro/memory_helpers.rb', line 14 def self.rss_bytes now = Process.clock_gettime(Process::CLOCK_MONOTONIC) cached = @rss_cache if cached && (now - cached[1]) < RSS_CACHE_TTL_SECONDS return cached[0] end value = read_rss_bytes @rss_cache_mutex.synchronize do # Re-check inside the lock to avoid racing a newer reading. cached = @rss_cache if cached.nil? || (now - cached[1]) >= RSS_CACHE_TTL_SECONDS @rss_cache = [value, now] end end value rescue 0 end |
.rss_mb ⇒ Object
34 35 36 37 38 |
# File 'lib/dead_bro/memory_helpers.rb', line 34 def self.rss_mb (rss_bytes.to_f / (1024 * 1024)).round(2) rescue 0.0 end |
.snapshot(label) ⇒ Object
Take a memory snapshot with a custom label
70 71 72 |
# File 'lib/dead_bro/memory_helpers.rb', line 70 def self.snapshot(label) DeadBro::MemoryTrackingSubscriber.take_memory_snapshot(label) end |
.top_allocators ⇒ Object
Get top memory allocating classes
142 143 144 145 146 147 |
# File 'lib/dead_bro/memory_helpers.rb', line 142 def self.top_allocators # This would need to be called from within a request context # where memory_events are available puts "Top memory allocators:" puts " (Call this from within a request to see allocation data)" end |