leak_profiler 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b9ed880d59ba3afb26bc0c8842545114d800d2e4466bde187118c70ea489ca4
4
- data.tar.gz: 9ac75655078d74b67928439f0ffb0493635075fee3226ebb4c37de6236bebd33
3
+ metadata.gz: 85fbefd746a7383bc1891bea286e39be5f311b55e9e1bd8a10f9e807939c5686
4
+ data.tar.gz: 9268c65c42714ec98accf5e4a3f2bf36383a2c539e26850542e27b475fe93f12
5
5
  SHA512:
6
- metadata.gz: 3e2ca40923c1f4baa23266d4f84b811af144e7f5c9feacdc054df13817066bd8c608ba55b99f5f9f50e471d17ce00938a3646e02962ba776b9b02e81ad86c594
7
- data.tar.gz: b8290c21265e17360816dd9f332f976a695c53d590b12aaeeb48324516ace274a88c47fc8bd43dff2d91686b263563de5472941183fcfd82aa0ae7c12456c491
6
+ metadata.gz: bf86b44edf7077e7d7ac6cc3c1af54379e3a5aaccfebced1a1b81aace9b1d6be2683b99d25cf8bf9e54492c0a14e405a003b93b5c4f522e9eb3839aabf6dbddb
7
+ data.tar.gz: 2778fbe72cbb71a5c2a4892f88b55dc01249a4f595ad4138eb15b7955c6ea09869ceae6f067d99ea1c5f92c3b7b0c0a5c045ae78c267321adfc66571c0b03c3f
data/.rubocop.yml CHANGED
@@ -38,6 +38,9 @@ Layout/MultilineAssignmentLayout:
38
38
  Layout/LineLength:
39
39
  Max: 180
40
40
 
41
+ Lint/IdentityComparison:
42
+ Enabled: false
43
+
41
44
  Lint/ConstantResolution:
42
45
  Enabled: false
43
46
 
data/README.md CHANGED
@@ -64,6 +64,7 @@ Referrers ----------------------------------------------------------------------
64
64
  * `interval` (default `30`): The interval in seconds for report.
65
65
  * `max_allocations` (default `10`): Outputs the specified number of objects that use a lot of memory.
66
66
  * `max_referrers` (default `3`): Outputs the number of references in order of the amount of memory used.
67
+ * `max_sample_objects` (default `100`): Sampling objects to detect referrer.
67
68
  * `logger` (defalut `nil`): Specify the logger object if you want to use custom logger.
68
69
  * `filename` (defalut `nil`): Specify the filename if you want to use custom filename.
69
70
 
@@ -3,20 +3,25 @@
3
3
  # rbs_inline: enabled
4
4
 
5
5
  require 'objspace'
6
+ require 'set'
6
7
 
7
8
  class LeakProfiler
8
9
  class Allocations
10
+ UNKNOWN = '<unknown>:<unknown>'
11
+ private_constant :UNKNOWN
12
+
9
13
  attr_reader :thread
10
14
 
11
15
  # @rbs logger: untyped
12
16
  # @rbs interval: Integer
13
17
  # @rbs max_allocations: Integer
14
18
  # @rbs max_referrers: Integer
15
- def initialize(logger:, interval:, max_allocations:, max_referrers:)
19
+ def initialize(logger:, interval:, max_allocations:, max_referrers:, max_sample_objects:)
16
20
  @logger = logger
17
21
  @interval = interval
18
22
  @max_allocations = max_allocations
19
23
  @max_referrers = max_referrers
24
+ @max_sample_objects = max_sample_objects
20
25
  end
21
26
 
22
27
  def report
@@ -37,13 +42,16 @@ class LeakProfiler
37
42
  end
38
43
 
39
44
  key = allocated_location(obj)
40
- next unless key
41
-
42
45
  allocations[key][:metrics] ||= Hash.new { |h, k| h[k] = 0 }
43
46
  allocations[key][:metrics][:count] += 1
44
47
  allocations[key][:metrics][:bytes] += ObjectSpace.memsize_of(obj)
45
48
 
46
- allocations[key][:sample_object] = obj
49
+ allocations[key][:sample_objects] ||= []
50
+ allocations[key][:sample_objects] << obj
51
+ end
52
+
53
+ allocations.each_value do |v|
54
+ v[:sample_objects] = v[:sample_objects].sample(@max_sample_objects)
47
55
  end
48
56
 
49
57
  report_allocations_class(allocations_by_class)
@@ -84,8 +92,10 @@ class LeakProfiler
84
92
  return if @max_referrers <= 0
85
93
 
86
94
  @logger.add(Logger::Severity::INFO, "Referrers #{"-" * 80}")
87
- sort(allocations).take(@max_referrers).each do |key, value|
88
- referrer_objects = detect_referrer_objects(value[:sample_object])
95
+
96
+ objs = allocations.reject { |k, _| k == UNKNOWN }
97
+ sort(objs).take(@max_referrers).each do |key, value|
98
+ referrer_objects = detect_referrer_objects(value[:sample_objects])
89
99
 
90
100
  logs = referrer_objects.map do |r|
91
101
  klass = obj_class(r[:referrer_object])
@@ -99,15 +109,15 @@ class LeakProfiler
99
109
  end
100
110
  end
101
111
 
102
- def detect_referrer_objects(object)
112
+ def detect_referrer_objects(objects)
103
113
  referrer_objects = []
114
+ objects_ids = objects.to_set(&:object_id)
115
+
104
116
  ObjectSpace.each_object.each do |obj|
105
117
  r = ObjectSpace.reachable_objects_from(obj)
106
118
  begin
107
- if r&.any? { |o| o.equal?(object) }
119
+ if r&.any? { |o| objects_ids.include?(o.object_id) }
108
120
  key = allocated_location(obj)
109
- next unless key
110
-
111
121
  referrer_objects << { referrer_object: obj, referrer_object_allocated_line: key }
112
122
  end
113
123
  rescue StandardError
@@ -117,9 +127,12 @@ class LeakProfiler
117
127
  end
118
128
 
119
129
  def allocated_location(obj)
120
- return unless ObjectSpace.allocation_sourcefile(obj)
130
+ file = ObjectSpace.allocation_sourcefile(obj)
131
+ return UNKNOWN if file.nil? || file.empty?
132
+
133
+ line = ObjectSpace.allocation_sourceline(obj)
121
134
 
122
- "#{ObjectSpace.allocation_sourcefile(obj)}:#{ObjectSpace.allocation_sourceline(obj)}"
135
+ "#{file}:#{line}"
123
136
  end
124
137
 
125
138
  def sort(allocations)
@@ -21,13 +21,14 @@ class LeakProfiler
21
21
  # @rbs interval: Integer
22
22
  # @rbs max_allocations: Integer
23
23
  # @rbs max_referrers: Integer
24
+ # @rbs max_sample_objects: Integer
24
25
  # @rbs logger: untyped
25
26
  # @rbs filename: String
26
27
  # @rbs return: self
27
- def report(interval: 30, max_allocations: 10, max_referrers: 3, logger: nil, filename: nil)
28
+ def report(interval: 30, max_allocations: 10, max_referrers: 3, max_sample_objects: 100, logger: nil, filename: nil)
28
29
  filename ||= "leak_profiler-#{Process.pid}.log"
29
30
  logger ||= Logger.new(File.join(@output_dir, filename))
30
- profiler = LeakProfiler::Allocations.new(logger: logger, interval: interval, max_allocations: max_allocations, max_referrers: max_referrers)
31
+ profiler = LeakProfiler::Allocations.new(logger: logger, interval: interval, max_allocations: max_allocations, max_referrers: max_referrers, max_sample_objects: max_sample_objects)
31
32
  profiler.report
32
33
  @threads << profiler.thread
33
34
 
@@ -2,13 +2,15 @@
2
2
 
3
3
  class LeakProfiler
4
4
  class Allocations
5
+ UNKNOWN: ::String
6
+
5
7
  attr_reader thread: untyped
6
8
 
7
9
  # @rbs logger: untyped
8
10
  # @rbs interval: Integer
9
11
  # @rbs max_allocations: Integer
10
12
  # @rbs max_referrers: Integer
11
- def initialize: (logger: untyped, interval: Integer, max_allocations: Integer, max_referrers: Integer) -> untyped
13
+ def initialize: (logger: untyped, interval: Integer, max_allocations: Integer, max_referrers: Integer, max_sample_objects: untyped) -> untyped
12
14
 
13
15
  def report: () -> untyped
14
16
 
@@ -20,7 +22,7 @@ class LeakProfiler
20
22
 
21
23
  def report_referrer_objects: (untyped allocations) -> untyped
22
24
 
23
- def detect_referrer_objects: (untyped object) -> untyped
25
+ def detect_referrer_objects: (untyped objects) -> untyped
24
26
 
25
27
  def allocated_location: (untyped obj) -> untyped
26
28
 
@@ -8,10 +8,11 @@ class LeakProfiler
8
8
  # @rbs interval: Integer
9
9
  # @rbs max_allocations: Integer
10
10
  # @rbs max_referrers: Integer
11
+ # @rbs max_sample_objects: Integer
11
12
  # @rbs logger: untyped
12
13
  # @rbs filename: String
13
14
  # @rbs return: self
14
- def report: (?interval: Integer, ?max_allocations: Integer, ?max_referrers: Integer, ?logger: untyped, ?filename: String) -> self
15
+ def report: (?interval: Integer, ?max_allocations: Integer, ?max_referrers: Integer, ?max_sample_objects: Integer, ?logger: untyped, ?filename: String) -> self
15
16
 
16
17
  # @rbs interval: Integer
17
18
  # @rbs filename: String
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leak_profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.5
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Watson