Advertisement
Guest User

Untitled

a guest
Aug 27th, 2015
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.11 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2. # Analyze heap dumps for memory leaks
  3. #
  4. # Gather the memory dumps with
  5. # bundle exec rbtrace — timeout 30 -e ‘load “#{Rails.root}/scripts/heap_dump.rb”’ -p $RAILS_PID
  6.  
  7. require 'set'
  8. require 'json'
  9.  
  10. if ARGV.length != 3
  11. puts "Usage: detect_leaks [FIRST.json] [SECOND.json] [THIRD.json]"
  12. exit 1
  13. end
  14.  
  15. first_addrs = Set.new
  16. third_addrs = Set.new
  17.  
  18. # Get a list of memory addresses from the first dump
  19. ignored_lines = 0
  20. File.open(ARGV[0], "r").each_line do |line|
  21. begin
  22. parsed = JSON.parse(line)
  23. first_addrs << parsed["address"] if parsed && parsed["address"]
  24. rescue
  25. ignored_lines += 1
  26. end
  27. end
  28. puts "Ignored #{ignored_lines} lines in first file"
  29.  
  30. # Get a list of memory addresses from the last dump
  31. ignored_lines = 0
  32. File.open(ARGV[2], "r").each_line do |line|
  33. begin
  34. parsed = JSON.parse(line)
  35. third_addrs << parsed["address"] if parsed && parsed["address"]
  36. rescue
  37. ignored_lines += 1
  38. end
  39. end
  40. puts "Ignored #{ignored_lines} lines in last file"
  41.  
  42. diff = []
  43.  
  44. # Get a list of all items present in both the second and
  45. # third dumps but not in the first.
  46. ignored_lines = 0
  47. File.open(ARGV[1], "r").each_line do |line|
  48. begin
  49. parsed = JSON.parse(line)
  50. if parsed && parsed["address"]
  51. if !first_addrs.include?(parsed["address"]) && third_addrs.include?(parsed["address"])
  52. diff << parsed
  53. end
  54. end
  55. rescue
  56. ignored_lines += 1
  57. end
  58. end
  59. puts "Ignored #{ignored_lines} lines in second file"
  60.  
  61. # Group items
  62. diff.group_by do |x|
  63. [x["type"], x["file"], x["line"]]
  64. end.map do |x,y|
  65. # Collect memory size
  66. [x, y.count, y.inject(0){|sum,i| sum + (i['bytesize'] || 0) }, y.inject(0){|sum,i| sum + (i['memsize'] || 0) }]
  67. end.sort do |a,b|
  68. b[1] <=> a[1]
  69. end.each do |x,y,bytesize,memsize|
  70. # Output information about each potential leak
  71. puts "Leaked #{y} #{x[0]} objects of size #{bytesize}/#{memsize} at: #{x[1]}:#{x[2]}"
  72. end
  73.  
  74. # Also output total memory usage, because why not?
  75. memsize = diff.inject(0){|sum,i| sum + (i['memsize'] || 0) }
  76. bytesize = diff.inject(0){|sum,i| sum + (i['bytesize'] || 0) }
  77. puts "\n\nTotal Size: #{bytesize}/#{memsize}"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement