-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory.rb
More file actions
101 lines (85 loc) · 1.99 KB
/
memory.rb
File metadata and controls
101 lines (85 loc) · 1.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/bin/env ruby
# lazy hack from Robert Klemme
module Memory
# sizes are guessed, I was too lazy to look
# them up and then they are also platform
# dependent
REF_SIZE = 4 # ?
OBJ_OVERHEAD = 4 # ?
FIXNUM_SIZE = 4 # ?
# informational output from analysis
MemoryInfo = Struct.new :roots, :objects, :bytes, :loops
def self.analyze(*roots)
an = Analyzer.new
an.roots = roots
an.analyze
end
class Analyzer
attr_accessor :roots
attr_reader :result
def analyze
@result = MemoryInfo.new roots, 0, 0, 0
@objs = {}
queue = roots.dup
until queue.empty?
obj = queue.shift
case obj
# special treatment for some types
# some are certainly missing from this
when IO
visit(obj)
when String
visit(obj) { @result.bytes += obj.size }
when Fixnum
@result.bytes += FIXNUM_SIZE
when Array
visit(obj) do
@result.bytes += obj.size * REF_SIZE
queue.concat(obj)
end
when Hash
visit(obj) do
@result.bytes += obj.size * REF_SIZE * 2
obj.each {|k,v| queue.push(k).push(v)}
end
when Enumerable
visit(obj) do
obj.each do |o|
@result.bytes += REF_SIZE
queue.push(o)
end
end
else
visit(obj) do
obj.instance_variables.each do |var|
@result.bytes += REF_SIZE
queue.push(obj.instance_variable_get(var))
end
end
end
end
@result
end
private
def visit(obj)
id = obj.object_id
if @objs.has_key? id
@result.loops += 1
false
else
@objs[id] = true
@result.bytes += OBJ_OVERHEAD
@result.objects += 1
yield obj if block_given?
true
end
end
end
end
h = {
"foo" => 2,
"bar" => 123,
}
h[5] = h
h[6] = h.keys
p Memory.analyze(h)