def profile_gc(app, env)
require 'objspace'
GC.start
stat = GC.stat
prev_gc_state = GC.disable
stat_before = object_space_stats
b = app.call(env)[2]
b.close if b.respond_to? :close
stat_after = object_space_stats
prev_gc_state ? GC.disable : GC.enable
diff = diff_object_stats(stat_before[:stats],stat_after[:stats])
string_analysis = analyze_strings(stat_before[:ids], stat_after[:ids])
new_objects, memory_allocated = analyze_growth(stat_before[:ids], stat_after[:ids])
objects_before, memory_before = analyze_initial_state(stat_before[:ids])
body = []
body << "
Overview
--------
Initial state: object count: #{objects_before}
Memory allocated outside heap (bytes): #{memory_before}
GC Stats:
--------
#{stat.map{|k,v| "#{k} : #{v}" }.sort!.join("\n")}
New bytes allocated outside of Ruby heaps: #{memory_allocated}
New objects: #{new_objects}
"
body << "
ObjectSpace delta caused by request:
-----------------------------------\n"
diff.to_a.delete_if{|_k, v| v == 0}.sort_by! { |_k, v| v }.reverse_each do |k,v|
body << "#{k} : #{v}\n"
end
body << "\n
ObjectSpace stats:
-----------------\n"
stat_after[:stats].to_a.sort_by!{ |_k, v| v }.reverse_each do |k,v|
body << "#{k} : #{v}\n"
end
body << "\n
String stats:
------------\n"
string_analysis.to_a.sort_by!{ |_k, v| -v }.take(1000).each do |string,count|
body << "#{count} : #{string}\n"
end
return [200, {'Content-Type' => 'text/plain'}, body]
ensure
prev_gc_state ? GC.disable : GC.enable
end