memory-profiler 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/Gemfile.lock +1 -1
  2. data/LICENSE +1 -2
  3. data/README +22 -3
  4. data/lib/memory-profiler.rb +301 -302
  5. metadata +24 -47
  6. data/Gemfile +0 -1
  7. data/Rakefile +0 -56
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- memory-profiler (1.0.1)
4
+ memory-profiler (1.0.2)
5
5
 
6
6
  GEM
7
7
  specs:
data/LICENSE CHANGED
@@ -10,5 +10,4 @@ Unless required by applicable law or agreed to in writing, software
10
10
  distributed under the License is distributed on an "AS IS" BASES,
11
11
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  See the License for the specific language governing permissions and
13
- limitations under the License.
14
-
13
+ limitations under the License.
data/README CHANGED
@@ -1,3 +1,25 @@
1
+ A rudimentary Ruby memory profiler that uses pure in-VM techniques to
2
+ analyse the object space and attempt to determine memory usage trends.
3
+
4
+ * Takes instantaneous snapshots, and can be used to determine trends
5
+ between subsequent instances.
6
+ * Can also be used to detect memory leaks (obscure object references,
7
+ etc.) in particular blocks or sections of code.
8
+
9
+ Note that this uses pure Ruby code and techniques, without patches to
10
+ the VM. As such it is trivial to install and use, but it doesn't have
11
+ access to raw memory management/garbage collection data, so is forced
12
+ to estimate, and it will affect performance noticeably.
13
+
14
+ It has been tested with the following Ruby versions (ruby -v):
15
+ * ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]
16
+ * ruby 1.9.1p243 (2009-07-16 revision 24175) [i486-linux]
17
+
18
+ This project was inspired by the similar Ruby memory profiler at
19
+ http://code.google.com/p/ruby-memory-profiler/ , which was apparently
20
+ released under a BSD (or BSD-style) license; but since no attribution
21
+ details were included, I haven't copied them here anywhere.
22
+
1
23
  -------------------------------------------------------------------------
2
24
 
3
25
  The simplest way to use this utility is to copy the file:
@@ -47,6 +69,3 @@ using the utility in your Ruby program:
47
69
  MemoryProfiler.stop_daemon
48
70
 
49
71
  -------------------------------------------------------------------------
50
-
51
- Report any issues to the author <matthew@kerwin.net.au>
52
-
@@ -3,8 +3,8 @@
3
3
  =begin
4
4
 
5
5
  Author: Matthew Kerwin <matthew@kerwin.net.au>
6
- Version: 1.0.1
7
- Date: 2011-01-31
6
+ Version: 1.0.2
7
+ Date: 2011-09-27
8
8
 
9
9
 
10
10
  Copyright 2011 Matthew Kerwin.
@@ -26,308 +26,307 @@
26
26
  require 'sync'
27
27
 
28
28
  module MemoryProfiler
29
- DEFAULTS = {
30
- # general options
31
- :sort_by => :current,
32
- :only => [],
33
- :ignore => [],
34
- :limit => 20,
35
- :force_gc => false,
36
- # daemon options
37
- :delay => 60,
38
- :filename => nil,
39
- # ObjectSpaceAnalyser options
40
- :string_debug => false,
41
- :marshall_size => false,
42
- }
43
- @@daemon_thread = nil
44
- @@daemon_sync = Sync.new
45
-
46
- @@start_data = nil
47
- @@start_sync = Sync.new
48
-
49
- #
50
- # Begins an analysis thread that runs periodically, reporting to a text
51
- # file at: /tmp/memory_profiler-<pid>.log
52
- #
53
- # Returns the filename used.
54
- #
55
- # Options:
56
- # :delay => 60 # number of seconds between summaries
57
- # :filename => nil # override the generated default
58
- # See: #start for other options
59
- #
60
- def self.start_daemon(opt = {})
61
- opt = DEFAULTS.merge(opt)
62
- filename = opt[:filename] || "/tmp/memory_profiler-#{Process.pid}.log"
63
- @@daemon_sync.synchronize(:EX) do
64
- raise 'daemon process already running' if @@daemon_thread
65
- @@daemon_thread = Thread.new do
66
- prev = Hash.new(0)
67
- file = File.open(filename, 'w')
68
- loop do
69
- begin
70
- GC.start if opt[:force_gc]
71
- curr = ObjectSpaceAnalyser.analyse(opt)
72
- data = self._delta(curr, prev, opt)
73
-
74
- file.puts '-'*80
75
- file.puts Time.now.to_s
76
- data.each {|k,c,d| file.printf( "%5d %+5d %s\n", c, d, k.name ) }
77
-
78
- prev = curr
79
- GC.start if opt[:force_gc]
80
- rescue ::Exception => err
81
- $stderr.puts "** MemoryProfiler daemon error: #{err}", err.backtrace.map{|b| "\t#{b}" }
82
- end
83
- sleep opt[:delay]
84
- end #loop
85
- end #Thread.new
86
- end
87
- filename
88
- end
89
-
90
- #
91
- # Terminates the analysis thread started by #start_daemon
92
- #
93
- def self.stop_daemon
94
- @@daemon_sync.synchronize(:EX) do
95
- raise 'no daemon process running' unless @@daemon_thread
96
- @@daemon_thread.kill
97
- @@daemon_thread.join
98
- @@daemon_thread = nil
99
- end
100
- self
101
- end
102
-
103
- #
104
- # Generates an instantaneous report on the current Ruby ObjectSpace, saved to
105
- # a text file at: /tmp/memory_profiler-<pid>-<time>.log
106
- #
107
- # Returns the filename used.
108
- #
109
- # See: #start for valid/default options, except that :sort_by may
110
- # only have the value :current or :none when using #report
111
- #
112
- def self.report(opt = {})
113
- opt = DEFAULTS.merge(opt)
114
- GC.start if opt[:force_gc]
115
-
116
- data = ObjectSpaceAnalyser.analyse(opt)
117
-
118
- if opt[:sort_by] == :current
119
- data = data.to_a.sort_by{|k,v| -v }
120
- data = data[0,opt[:limit]] if opt[:limit] > 0 and opt[:limit] < data.length
121
- elsif opt[:sort_by] != :none
122
- warn "MemoryProfiler: invalid option :sort_by => #{opt[:sort_by].inspect}; using :none"
123
- end
124
-
125
- filename = opt[:filename] || "/tmp/memory_profiler-#{Process.pid}-#{Time.now.to_i}.log"
126
- File.open(filename, 'w') do |f|
127
- data.each {|k,c| file.printf( "%5d %s\n", c, k.name ) }
128
- end
129
-
130
- GC.start if opt[:force_gc]
131
- filename
132
- end
133
-
134
- #
135
- # If a block is given, executes it and returns a summary. Otherwise,
136
- # starts the analyser, and waits for a call to #restart or #stop.
137
- #
138
- # Returned data is an array of:
139
- # [ [Class, current_usage, usage_delta], ... ]
140
- #
141
- # Options:
142
- # :sort_by => :current # how to order classes; :current | :delta | :absdelta | :none
143
- #
144
- # :only => [] # list of only classes to scan; if empty, scans all classes
145
- # :ignore => [] # list of classes to exclude from reports (including sub-classes and modules, but not namespaces)
146
- # :limit => 20 # how many of the top classes to report (less than 1 means 'all'); only matters if :sort_by is not :none
147
- #
148
- # :force_gc => true # if true, forces a garbage collection before and after generating report
149
- #
150
- # :string_debug => false # see ObjectSpaceAnalyser#analyse
151
- # :marshall_size => false # see ObjectSpaceAnalyser#analyse
152
- #
153
- def self.start(opt = {}, &block)
154
- opt = DEFAULTS.merge(opt)
155
- if block_given?
156
- # get pre-block analysis of ObjectSpace
157
- GC.start if opt[:force_gc]
158
- prev = ObjectSpaceAnalyser.analyse(opt)
159
- GC.start if opt[:force_gc]
160
-
161
- yield
162
-
163
- # get post-block analysis of ObjectSpace
164
- GC.start if opt[:force_gc]
165
- curr = ObjectSpaceAnalyser.analyse(opt)
166
-
167
- # calculate the differences before and after execution
168
- data = self._delta(curr, prev, opt)
169
-
170
- # return it
171
- GC.start if opt[:force_gc]
172
- data
173
- else
174
- @@start_sync.synchronize(:EX) do
175
- raise 'already started' if @@start_data
176
-
177
- GC.start if opt[:force_gc]
178
- @@start_data = [ObjectSpaceAnalyser.analyse(opt), opt]
179
- GC.start if opt[:force_gc]
180
- end
181
- self
182
- end
183
- end
184
-
185
- #
186
- # Stops the current analysis and emits the results.
187
- #
188
- # See: #start
189
- #
190
- def self.stop
191
- prev = nil
192
- opt = nil
193
- @@start_sync.synchronize(:EX) do
194
- raise 'not started' unless @@start_data
195
- prev, opt = @@start_data
196
- @@start_data = nil
197
- end
198
-
199
- # get the current state of affairs
200
- GC.start if opt[:force_gc]
201
- curr = ObjectSpaceAnalyser.analyse(opt)
202
-
203
- # calculate the differences before and after execution
204
- data = self._delta(curr, prev, opt)
205
-
206
- # return it
207
- GC.start if opt[:force_gc]
208
- data
209
- end
210
-
211
- #
212
- # Stops the current analysis, emits the results, and immediately starts
213
- # a new analysis.
214
- #
215
- # See: #stop, #start
216
- #
217
- def self.restart(opt = {})
218
- res = self.stop
219
- self.start(opt)
220
- res
221
- end
222
-
223
- # => [ [Class, current, delta], ... ]
224
- def self._delta(curr, prev, opt={}) #:nodoc:
225
- opt = DEFAULTS.merge(opt)
226
-
227
- # determine the difference between current and previous
228
- delta = Hash.new(0)
229
- (curr.keys + prev.keys).each do |k|
230
- delta[k] = curr[k] - prev[k]
231
- end
232
- data = delta.map{|k,d| [k, curr[k].to_i, d]}
233
-
234
- # organise data according to given options
235
- case opt[:sort_by]
236
- when :none
237
- opt[:limit] = -1
238
- when :current
239
- data = data.sort_by{|k,c,d| -( c ) }
240
- when :delta
241
- data = data.sort_by{|k,c,d| -( d ) }
242
- when :absdelta
243
- data = data.sort_by{|k,c,d| -( d.abs ) }
244
- else
245
- warn "MemoryProfiler: invalid option :sort_by => #{opt[:sort_by].inspect}; using :none"
246
- opt[:limit] = -1
247
- end
248
- data = data[0,opt[:limit]] if opt[:limit] > 0 and opt[:limit] < data.length
249
-
250
- # return it
251
- data
252
- end
253
-
254
- #
255
- # Formats data, such as that returned by #start , into a printable,
256
- # readable string.
257
- #
258
- def self.format(data)
259
- " Curr. Delta Class\n" +
260
- " ----- ----- -----\n" +
261
- data.map{|k,c,d| sprintf(" %5d %+5d %s\n", c, d, k.name) }.join
262
- end
263
-
264
-
265
- module ObjectSpaceAnalyser
266
- #
267
- # Returns a hash mapping each Class to its usage.
268
- #
269
- # If opt[:marshall_size] is true, the usage is estimated using Marshall.dump() for each instance;
270
- # otherwise it is a simple instance count.
271
- #
272
- # If opt[:string_debug] is true, the analyser writes a text file containing every string
273
- # in the Ruby ObjectSpace, at: /tmp/memory_profiler-<pid>-strings-<time>.log
274
- #
275
- # Uses opt[:only] and opt[:ignore] , as per MemoryProfiler#start
276
- #
277
- def self.analyse(opt = {})
278
- opt = MemoryProfiler::DEFAULTS.merge(opt)
279
- marshall_size = !!opt[:marshall_size]
280
- string_debug = !!opt[:string_debug]
281
- ign = opt[:ignore]
282
- only = opt[:only]
283
-
284
- res = Hash.new(0)
285
- str = [] if string_debug
286
- ObjectSpace.each_object do |o|
287
- if res[o.class] or ((only.empty? or only.any?{|y| o.is_a? y }) and ign.none?{|x| o.is_a? x })
288
- res[o.class] += (marshall_size ? self.__sizeof(o) : 1)
289
- end
290
- str.push o.inspect if string_debug and o.class == String
291
- end
292
- if string_debug
293
- self.__save str
294
- str = nil
295
- end
296
- res
297
- end
298
-
299
- # Estimates the size of an object using Marshall.dump()
300
- # Defaults to 1 if anything goes wrong.
301
- def self.__sizeof(o) #:nodoc:
302
- Marshall.dump(o).size
303
- rescue ::Exception
304
- 1
305
- end
306
-
307
- # a single place where the magic filename is defined
308
- def self.__save(str) #:nodoc:
309
- File.open("/tmp/memory_profiler-#{Process.pid}-strings-#{Time.now.to_i}.log", 'w') do |f|
310
- str.sort.each{|s| f.puts s }
311
- end
312
- str = nil
313
- end
314
- end
29
+ DEFAULTS = {
30
+ # general options
31
+ :sort_by => :current,
32
+ :only => [],
33
+ :ignore => [],
34
+ :limit => 20,
35
+ :force_gc => false,
36
+ # daemon options
37
+ :delay => 60,
38
+ :filename => nil,
39
+ # ObjectSpaceAnalyser options
40
+ :string_debug => false,
41
+ :marshall_size => false,
42
+ }
43
+ @@daemon_thread = nil
44
+ @@daemon_sync = Sync.new
45
+
46
+ @@start_data = nil
47
+ @@start_sync = Sync.new
48
+
49
+ #
50
+ # Begins an analysis thread that runs periodically, reporting to a text
51
+ # file at: /tmp/memory_profiler-<pid>.log
52
+ #
53
+ # Returns the filename used.
54
+ #
55
+ # Options:
56
+ # :delay => 60 # number of seconds between summaries
57
+ # :filename => nil # override the generated default
58
+ # See: #start for other options
59
+ #
60
+ def self.start_daemon(opt = {})
61
+ opt = DEFAULTS.merge(opt)
62
+ filename = opt[:filename] || "/tmp/memory_profiler-#{Process.pid}.log"
63
+ @@daemon_sync.synchronize(:EX) do
64
+ raise 'daemon process already running' if @@daemon_thread
65
+ @@daemon_thread = Thread.new do
66
+ prev = Hash.new(0)
67
+ file = File.open(filename, 'w')
68
+ loop do
69
+ begin
70
+ GC.start if opt[:force_gc]
71
+ curr = ObjectSpaceAnalyser.analyse(opt)
72
+ data = self._delta(curr, prev, opt)
73
+
74
+ file.puts '-'*80
75
+ file.puts Time.now.to_s
76
+ data.each {|k,c,d| file.printf( "%5d %+5d %s\n", c, d, k.name ) }
77
+
78
+ prev = curr
79
+ GC.start if opt[:force_gc]
80
+ rescue ::Exception => err
81
+ $stderr.puts "** MemoryProfiler daemon error: #{err}", err.backtrace.map{|b| "\t#{b}" }
82
+ end
83
+ sleep opt[:delay]
84
+ end #loop
85
+ end #Thread.new
86
+ end
87
+ filename
88
+ end
89
+
90
+ #
91
+ # Terminates the analysis thread started by #start_daemon
92
+ #
93
+ def self.stop_daemon
94
+ @@daemon_sync.synchronize(:EX) do
95
+ raise 'no daemon process running' unless @@daemon_thread
96
+ @@daemon_thread.kill
97
+ @@daemon_thread.join
98
+ @@daemon_thread = nil
99
+ end
100
+ self
101
+ end
102
+
103
+ #
104
+ # Generates an instantaneous report on the current Ruby ObjectSpace, saved to
105
+ # a text file at: /tmp/memory_profiler-<pid>-<time>.log
106
+ #
107
+ # Returns the filename used.
108
+ #
109
+ # See: #start for valid/default options, except that :sort_by may
110
+ # only have the value :current or :none when using #report
111
+ #
112
+ def self.report(opt = {})
113
+ opt = DEFAULTS.merge(opt)
114
+ GC.start if opt[:force_gc]
115
+
116
+ data = ObjectSpaceAnalyser.analyse(opt)
117
+
118
+ if opt[:sort_by] == :current
119
+ data = data.to_a.sort_by{|k,v| -v }
120
+ data = data[0,opt[:limit]] if opt[:limit] > 0 and opt[:limit] < data.length
121
+ elsif opt[:sort_by] != :none
122
+ warn "MemoryProfiler: invalid option :sort_by => #{opt[:sort_by].inspect}; using :none"
123
+ end
124
+
125
+ filename = opt[:filename] || "/tmp/memory_profiler-#{Process.pid}-#{Time.now.to_i}.log"
126
+ File.open(filename, 'w') do |f|
127
+ data.each {|k,c| f.printf( "%5d %s\n", c, k.name ) }
128
+ end
129
+
130
+ GC.start if opt[:force_gc]
131
+ filename
132
+ end
133
+
134
+ #
135
+ # If a block is given, executes it and returns a summary. Otherwise,
136
+ # starts the analyser, and waits for a call to #restart or #stop.
137
+ #
138
+ # Returned data is an array of:
139
+ # [ [Class, current_usage, usage_delta], ... ]
140
+ #
141
+ # Options:
142
+ # :sort_by => :current # how to order classes; :current | :delta | :absdelta | :none
143
+ #
144
+ # :only => [] # list of only classes to scan; if empty, scans all classes
145
+ # :ignore => [] # list of classes to exclude from reports (including sub-classes and modules, but not namespaces)
146
+ # :limit => 20 # how many of the top classes to report (less than 1 means 'all'); only matters if :sort_by is not :none
147
+ #
148
+ # :force_gc => true # if true, forces a garbage collection before and after generating report
149
+ #
150
+ # :string_debug => false # see ObjectSpaceAnalyser#analyse
151
+ # :marshall_size => false # see ObjectSpaceAnalyser#analyse
152
+ #
153
+ def self.start(opt = {}, &block)
154
+ opt = DEFAULTS.merge(opt)
155
+ if block_given?
156
+ # get pre-block analysis of ObjectSpace
157
+ GC.start if opt[:force_gc]
158
+ prev = ObjectSpaceAnalyser.analyse(opt)
159
+ GC.start if opt[:force_gc]
160
+
161
+ yield
162
+
163
+ # get post-block analysis of ObjectSpace
164
+ GC.start if opt[:force_gc]
165
+ curr = ObjectSpaceAnalyser.analyse(opt)
166
+
167
+ # calculate the differences before and after execution
168
+ data = self._delta(curr, prev, opt)
169
+
170
+ # return it
171
+ GC.start if opt[:force_gc]
172
+ data
173
+ else
174
+ @@start_sync.synchronize(:EX) do
175
+ raise 'already started' if @@start_data
176
+
177
+ GC.start if opt[:force_gc]
178
+ @@start_data = [ObjectSpaceAnalyser.analyse(opt), opt]
179
+ GC.start if opt[:force_gc]
180
+ end
181
+ self
182
+ end
183
+ end
184
+
185
+ #
186
+ # Stops the current analysis and emits the results.
187
+ #
188
+ # See: #start
189
+ #
190
+ def self.stop
191
+ prev = nil
192
+ opt = nil
193
+ @@start_sync.synchronize(:EX) do
194
+ raise 'not started' unless @@start_data
195
+ prev, opt = @@start_data
196
+ @@start_data = nil
197
+ end
198
+
199
+ # get the current state of affairs
200
+ GC.start if opt[:force_gc]
201
+ curr = ObjectSpaceAnalyser.analyse(opt)
202
+
203
+ # calculate the differences before and after execution
204
+ data = self._delta(curr, prev, opt)
205
+
206
+ # return it
207
+ GC.start if opt[:force_gc]
208
+ data
209
+ end
210
+
211
+ #
212
+ # Stops the current analysis, emits the results, and immediately starts
213
+ # a new analysis.
214
+ #
215
+ # See: #stop, #start
216
+ #
217
+ def self.restart(opt = {})
218
+ res = self.stop
219
+ self.start(opt)
220
+ res
221
+ end
222
+
223
+ # => [ [Class, current, delta], ... ]
224
+ def self._delta(curr, prev, opt={}) #:nodoc:
225
+ opt = DEFAULTS.merge(opt)
226
+
227
+ # determine the difference between current and previous
228
+ delta = Hash.new(0)
229
+ (curr.keys + prev.keys).each do |k|
230
+ delta[k] = curr[k] - prev[k]
231
+ end
232
+ data = delta.map{|k,d| [k, curr[k].to_i, d]}
233
+
234
+ # organise data according to given options
235
+ case opt[:sort_by]
236
+ when :none
237
+ opt[:limit] = -1
238
+ when :current
239
+ data = data.sort_by{|k,c,d| -( c ) }
240
+ when :delta
241
+ data = data.sort_by{|k,c,d| -( d ) }
242
+ when :absdelta
243
+ data = data.sort_by{|k,c,d| -( d.abs ) }
244
+ else
245
+ warn "MemoryProfiler: invalid option :sort_by => #{opt[:sort_by].inspect}; using :none"
246
+ opt[:limit] = -1
247
+ end
248
+ data = data[0,opt[:limit]] if opt[:limit] > 0 and opt[:limit] < data.length
249
+
250
+ # return it
251
+ data
252
+ end
253
+
254
+ #
255
+ # Formats data, such as that returned by #start , into a printable,
256
+ # readable string.
257
+ #
258
+ def self.format(data)
259
+ " Curr. Delta Class\n" +
260
+ " ----- ----- -----\n" +
261
+ data.map{|k,c,d| sprintf(" %5d %+5d %s\n", c, d, k.name) }.join
262
+ end
263
+
264
+
265
+ module ObjectSpaceAnalyser
266
+ #
267
+ # Returns a hash mapping each Class to its usage.
268
+ #
269
+ # If opt[:marshall_size] is true, the usage is estimated using Marshall.dump() for each instance;
270
+ # otherwise it is a simple instance count.
271
+ #
272
+ # If opt[:string_debug] is true, the analyser writes a text file containing every string
273
+ # in the Ruby ObjectSpace, at: /tmp/memory_profiler-<pid>-strings-<time>.log
274
+ #
275
+ # Uses opt[:only] and opt[:ignore] , as per MemoryProfiler#start
276
+ #
277
+ def self.analyse(opt = {})
278
+ opt = MemoryProfiler::DEFAULTS.merge(opt)
279
+ marshall_size = !!opt[:marshall_size]
280
+ string_debug = !!opt[:string_debug]
281
+ ign = opt[:ignore]
282
+ only = opt[:only]
283
+
284
+ res = Hash.new(0)
285
+ str = [] if string_debug
286
+ ObjectSpace.each_object do |o|
287
+ if res[o.class] or ((only.empty? or only.any?{|y| o.is_a? y }) and ign.none?{|x| o.is_a? x })
288
+ res[o.class] += (marshall_size ? self.__sizeof(o) : 1)
289
+ end
290
+ str.push o.inspect if string_debug and o.class == String
291
+ end
292
+ if string_debug
293
+ self.__save str
294
+ str = nil
295
+ end
296
+ res
297
+ end
298
+
299
+ # Estimates the size of an object using Marshall.dump()
300
+ # Defaults to 1 if anything goes wrong.
301
+ def self.__sizeof(o) #:nodoc:
302
+ Marshall.dump(o).size
303
+ rescue ::Exception
304
+ 1
305
+ end
306
+
307
+ # a single place where the magic filename is defined
308
+ def self.__save(str) #:nodoc:
309
+ File.open("/tmp/memory_profiler-#{Process.pid}-strings-#{Time.now.to_i}.log", 'w') do |f|
310
+ str.sort.each{|s| f.puts s }
311
+ end
312
+ str = nil
313
+ end
314
+ end
315
315
  end
316
316
 
317
317
 
318
318
  if $0 == __FILE__
319
- puts MemoryProfiler.start_daemon( :limit=>5, :delay=>10, :marshall_size=>true, :sort_by=>:absdelta )
320
-
321
- 5.times do
322
- blah = Hash.new([])
323
- rpt = MemoryProfiler.start( :limit=>10 ) do
324
- 100.times{ blah[1] << 'aaaaa' }
325
- 1000.times{ blah[2] << 'bbbbb' }
326
- end
327
- puts MemoryProfiler.format(rpt)
328
- sleep 7
329
- end
330
-
331
- MemoryProfiler.stop_daemon
319
+ puts MemoryProfiler.start_daemon( :limit=>5, :delay=>10, :marshall_size=>true, :sort_by=>:absdelta )
320
+
321
+ 5.times do
322
+ blah = Hash.new([])
323
+ rpt = MemoryProfiler.start( :limit=>10 ) do
324
+ 100.times{ blah[1] << 'aaaaa' }
325
+ 1000.times{ blah[2] << 'bbbbb' }
326
+ end
327
+ puts MemoryProfiler.format(rpt)
328
+ sleep 7
329
+ end
330
+
331
+ MemoryProfiler.stop_daemon
332
332
  end
333
-
metadata CHANGED
@@ -1,81 +1,58 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: memory-profiler
3
- version: !ruby/object:Gem::Version
4
- hash: 21
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- - 1
10
- version: 1.0.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Matthew Kerwin
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-01-31 00:00:00 +10:00
19
- default_executable:
12
+ date: 2013-02-27 00:00:00.000000000 Z
20
13
  dependencies: []
21
-
22
- description: A rudimentary memory profiler that uses pure in-VM techniques to analyse the object space and attempt to determine memory usage trends.
23
- email:
14
+ description: A rudimentary memory profiler that uses pure in-VM techniques to analyse
15
+ the object space and attempt to determine memory usage trends.
16
+ email:
24
17
  - matthew@kerwin.net.au
25
18
  executables: []
26
-
27
19
  extensions: []
28
-
29
20
  extra_rdoc_files: []
30
-
31
- files:
21
+ files:
32
22
  - lib/memory-profiler.rb
33
- - Rakefile
34
23
  - LICENSE
35
24
  - README
36
25
  - Gemfile.lock
37
- - Gemfile
38
- has_rdoc: true
39
- homepage: http://code.google.com/p/memory-profiler-ruby/
40
- licenses:
26
+ homepage: https://github.com/phluid61/memory-profiler-gem
27
+ licenses:
41
28
  - Apache License 2.0
42
29
  post_install_message:
43
- rdoc_options:
30
+ rdoc_options:
44
31
  - --title
45
32
  - Memory Profiler
46
33
  - --main
47
34
  - MemoryProfiler
48
35
  - --line-numbers
49
36
  - --tab-width
50
- - "2"
51
- require_paths:
37
+ - '2'
38
+ require_paths:
52
39
  - lib
53
- required_ruby_version: !ruby/object:Gem::Requirement
40
+ required_ruby_version: !ruby/object:Gem::Requirement
54
41
  none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 3
59
- segments:
60
- - 0
61
- version: "0"
62
- required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
47
  none: false
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- hash: 23
68
- segments:
69
- - 1
70
- - 3
71
- - 6
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
72
51
  version: 1.3.6
73
52
  requirements: []
74
-
75
53
  rubyforge_project: mem-prof-ruby
76
- rubygems_version: 1.4.2
54
+ rubygems_version: 1.8.11
77
55
  signing_key:
78
56
  specification_version: 3
79
57
  summary: A Ruby Memory Profiler
80
58
  test_files: []
81
-
data/Gemfile DELETED
@@ -1 +0,0 @@
1
- gemspec
data/Rakefile DELETED
@@ -1,56 +0,0 @@
1
- gemspec = eval(File.read(Dir["*.gemspec"].first))
2
-
3
- begin
4
- require 'bundler'
5
- Bundler.setup
6
- rescue LoadError => er
7
- $stderr.puts "You need to have Bundler installed to be able to build this gem."
8
- # Process.exit
9
- end
10
-
11
- # This is hacky, but I'm too lazy right now to compare all executables in the $PATH
12
- # and try to work out which gem* command is appropriate.
13
- if $0 =~ /\brake((?:\d+[.\d]))$/
14
- $version = $1
15
- else
16
- $version = case RUBY_VERSION
17
- when /^(1\.\d)\.0$/ then $1
18
- when /^1\.8\./ then '1.8'
19
- else RUBY_VERSION
20
- end
21
- end
22
-
23
- desc "Validate the gemspec"
24
- task :gemspec do
25
- gemspec.validate
26
- end
27
-
28
- desc "Build gem locally"
29
- task :build => :gemspec do
30
- system "gem#$version build #{gemspec.name}.gemspec"
31
- FileUtils.mkdir_p "pkg-#$version"
32
- FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg-#$version"
33
- end
34
-
35
- desc "Install gem locally"
36
- task :install => :build do
37
- system "gem#$version install pkg-#$version/#{gemspec.name}-#{gemspec.version}"
38
- end
39
-
40
- desc "Publish gem"
41
- task :push => :build do
42
- system "gem#$version push pkg-#$version/#{gemspec.name}-#{gemspec.version}"
43
- end
44
-
45
-
46
- desc "Generate rdoc documentation"
47
- task :rdoc do
48
- system "rdoc#$version #{gemspec.rdoc_options.map{|o| o =~ /\s/ ? '"'+o+'"' : o}.join(' ')}"
49
- end
50
-
51
-
52
- desc "Clean automatically generated files"
53
- task :clean do
54
- FileUtils.rm_rf "pkg-#$version"
55
- end
56
-