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 +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +1 -0
- data/lib/leak_profiler/allocations.rb +25 -12
- data/lib/leak_profiler/leak_profiler.rb +3 -2
- data/sig/generated/leak_profiler/allocations.rbs +4 -2
- data/sig/generated/leak_profiler/leak_profiler.rbs +2 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85fbefd746a7383bc1891bea286e39be5f311b55e9e1bd8a10f9e807939c5686
|
4
|
+
data.tar.gz: 9268c65c42714ec98accf5e4a3f2bf36383a2c539e26850542e27b475fe93f12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf86b44edf7077e7d7ac6cc3c1af54379e3a5aaccfebced1a1b81aace9b1d6be2683b99d25cf8bf9e54492c0a14e405a003b93b5c4f522e9eb3839aabf6dbddb
|
7
|
+
data.tar.gz: 2778fbe72cbb71a5c2a4892f88b55dc01249a4f595ad4138eb15b7955c6ea09869ceae6f067d99ea1c5f92c3b7b0c0a5c045ae78c267321adfc66571c0b03c3f
|
data/.rubocop.yml
CHANGED
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][:
|
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
|
-
|
88
|
-
|
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(
|
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|
|
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
|
-
|
130
|
+
file = ObjectSpace.allocation_sourcefile(obj)
|
131
|
+
return UNKNOWN if file.nil? || file.empty?
|
132
|
+
|
133
|
+
line = ObjectSpace.allocation_sourceline(obj)
|
121
134
|
|
122
|
-
"#{
|
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
|
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
|