# Dike-0.0.4

**URL:** <https://www.ruby-forum.com/t/dike-0-0-4/125507>\
**Category:** Ruby\
**Created:** [January 9, 2008, 7:52pm UTC](https://www.ruby-forum.com/t/dike-0-0-4/125507 "2008-01-09T19:52:20Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![ara\_howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d9b06d/32.png) [@ara\_howard](https://www.ruby-forum.com/u/ara_howard)\
**Post date:** [January 9, 2008, 7:52pm UTC](https://www.ruby-forum.com/t/dike-0-0-4/125507/1 "2008-01-09T19:52:20Z")

</div>

NAME

dike

SYNOPSIS

a simple memory leak detector for ruby with preconfigured rails  
hooks.

INSTALL

gem install dike

URIS

[http://www.codeforpeople.com/lib/ruby/](http://www.codeforpeople.com/lib/ruby/)  
[http://rubyforge.org/projects/codeforpeople/](http://rubyforge.org/projects/codeforpeople/)

DESCRIPTION

the concept behind dike.rb is simple: class Object is extended in  
order that  
the location of each object’s creation is tracked. a summarizer  
command is  
given to walk ObjectSpace using each object’s class and the  
location if it’s  
creation to detect memory leaks. not all leaks can be detected and  
some that  
are may not really be leaks, but dike provided a simple way to see  
the  
hotspots in your code that may potentially be leaking.

HISTORY

0.0.4:

```
 - under rare circumstances dike itself interacted strangely with

```

certain  
classes and caused them to leak, HTTPOK was one such example.  
this  
release fixes that bug. thanks to Jan Kubr for providing a  
great test  
case that helped me fix this.

EXAMPLES

### PURE RUBY

```
## just dumping sequential snapshots to stderr, looking at a

```

specific class

```
 # cfp:~ > cat sample/a.rb
     require 'dike'

     class Leak < ::String
     end

     Leaks = Array.new

     Dike.filter Leak

     loop do
       Leaks << Leak.new('leak' * 1024)
       Dike.finger
       sleep 1
     end

 # cfp:~ > ruby sample/a.rb | less
     ---
     - class: Leak
       count: 2
       trace:
       - sample/a.rb:11
       - sample/a.rb:10:in `loop'
       - sample/a.rb:10
     ---
     - class: Leak
       count: 3
       trace:
       - sample/a.rb:11
       - sample/a.rb:10:in `loop'
       - sample/a.rb:10
     ---
     - class: Leak
       count: 4
       trace:
       - sample/a.rb:11
       - sample/a.rb:10:in `loop'
       - sample/a.rb:10
     ---
     - class: Leak
       count: 5
       trace:
       - sample/a.rb:11
       - sample/a.rb:10:in `loop'
       - sample/a.rb:10
     ---
     - class: Leak
       count: 6
       trace:
       - sample/a.rb:11
       - sample/a.rb:10:in `loop'
       - sample/a.rb:10

## dumping sequential snapshots using Dike.logfactory and then

```

using the ‘dike’  
command line tool to do comparisons of the dumped snapshots

```
 # cfp:~ > cat sample/b.rb
     require 'dike'

     Leaks = Array.new

     class Leak
       def initialize
         @leak = 42.chr * (2 ** 20)
       end
     end

     Dike.logfactory './log/'

     Dike.finger

     3.times{ Leaks << Leak.new }

     Dike.finger

     2.times{ Leaks << Leak.new }

     Dike.finger

 # cfp:~ > ruby sample/b.rb

 # cfp:~ > ls log/
     0 1 2

 # cfp:~ > dike log/
     ---
     - class: Leak
       count: 3
       trace:
       - sample/b.rb:15
       - sample/b.rb:15:in `times'
       - sample/b.rb:15
     - class: Leak
       count: 2
       trace:
       - sample/b.rb:19
       - sample/b.rb:19:in `times'
       - sample/b.rb:19

 # cfp:~ > dike log/0 log/1
     ---
     - class: Leak
       count: 3
       trace:
       - sample/b.rb:15
       - sample/b.rb:15:in `times'
       - sample/b.rb:15

 # cfp:~ > dike log/1 log/2
     ---
     - class: Leak
       count: 2
       trace:
       - sample/b.rb:19
       - sample/b.rb:19:in `times'
       - sample/b.rb:19

```

### RAILS

```
 # cfp:~ > cat ./config/environment.rb
   ...
   require 'dike'
   Dike.on :rails

 # cfp:~ > ./script/server

 # cfp:~ > curl --silent http://localhost:3000 >/dev/null

 # cfp:~ > cat ./log/dike/0
   ---
   - class: String
     count: 90769
     trace: []
   - class: Array
     count: 18931
     trace: []
   - class: Class
     count: 2
     trace:
     - votelink.com/public/../config/../lib/widgets.rb:222:in

```

`class_factory' - votelink.com/public/../config/../lib/widgets.rb:220:in `each’  
- [votelink.com/public/../config/../lib/widgets.rb:220:in](http://votelink.com/public/../config/../lib/widgets.rb:220:in)  
`class_factory' - votelink.com/public/../config/../lib/widgets.rb:248:in `Widget’  
- [votelink.com/public/../config/../lib/widgets/page/base.rb:1](http://votelink.com/public/../config/../lib/widgets/page/base.rb:1)  
- [votelink.com/public/../config/../lib/widgets.rb:31:in](http://votelink.com/public/../config/../lib/widgets.rb:31:in)  
`require' - votelink.com/public/../config/../lib/widgets.rb:31:in `load’  
- [votelink.com/public/../config/../lib/widgets.rb:16:in](http://votelink.com/public/../config/../lib/widgets.rb:16:in)  
`for_controller' - votelink.com/public/../config/../lib/widgets.rb:243:in `widget’  
- [votelink.com/public/../config/../app/controllers/](http://votelink.com/public/../config/../app/controllers/)  
application.rb:150  
…

```
 # cfp:~ > curl --silent http://localhost:3000 >/dev/null

 # cfp:~ > cat ./log/dike/1
   ---
   - class: String
     count: 100769
     trace: []
   - class: Array
     count: 19931
     trace: []
   - class: Class
     count: 5
     trace:
     - votelink.com/public/../config/../lib/widgets.rb:222:in

```

`class_factory' - votelink.com/public/../config/../lib/widgets.rb:220:in `each’  
- [votelink.com/public/../config/../lib/widgets.rb:220:in](http://votelink.com/public/../config/../lib/widgets.rb:220:in)  
`class_factory' - votelink.com/public/../config/../lib/widgets.rb:248:in `Widget’  
- [votelink.com/public/../config/../lib/widgets/page/base.rb:1](http://votelink.com/public/../config/../lib/widgets/page/base.rb:1)  
- [votelink.com/public/../config/../lib/widgets.rb:31:in](http://votelink.com/public/../config/../lib/widgets.rb:31:in)  
`require' - votelink.com/public/../config/../lib/widgets.rb:31:in `load’  
- [votelink.com/public/../config/../lib/widgets.rb:16:in](http://votelink.com/public/../config/../lib/widgets.rb:16:in)  
`for_controller' - votelink.com/public/../config/../lib/widgets.rb:243:in `widget’  
- [votelink.com/public/../config/../app/controllers/](http://votelink.com/public/../config/../app/controllers/)  
application.rb:150  
…

```
 # cfp:~ > dike ./log/dike
   ...
   - class: Class
     count: 3
     trace:
     - votelink.com/public/../config/../lib/widgets.rb:222:in

```

`class_factory' - votelink.com/public/../config/../lib/widgets.rb:220:in `each’  
- [votelink.com/public/../config/../lib/widgets.rb:220:in](http://votelink.com/public/../config/../lib/widgets.rb:220:in)  
`class_factory' - votelink.com/public/../config/../lib/widgets.rb:248:in `Widget’  
- [votelink.com/public/../config/../lib/widgets/page/base.rb:1](http://votelink.com/public/../config/../lib/widgets/page/base.rb:1)  
- [votelink.com/public/../config/../lib/widgets.rb:31:in](http://votelink.com/public/../config/../lib/widgets.rb:31:in)  
`require' - votelink.com/public/../config/../lib/widgets.rb:31:in `load’  
- [votelink.com/public/../config/../lib/widgets.rb:16:in](http://votelink.com/public/../config/../lib/widgets.rb:16:in)  
`for_controller' - votelink.com/public/../config/../lib/widgets.rb:243:in `widget’  
- [votelink.com/public/../config/../app/controllers/](http://votelink.com/public/../config/../app/controllers/)  
application.rb:150  
…

NOTES

- the ‘Dike.finger’ method dumps it’s log in a format showing

- loading into a rails environment causes snapshots of the above  
format to  
be dumped into RAILS\_ROOT/log/dike/ after each request. each  
snapshot is  
incrementally numbered 0, 1, …

- the ‘dike’ command line tool can be used in two ways

- options that affect logging

LIMITATIONS

not all object creation can be tracked. not all leaks are reported.  
some  
reported leaks are not. dike shows you where in the source objects  
are being  
created that cannot be reclaimed - these are not always leaks as  
this line

```
 class C; end

```

shows. the class ‘C’ cannot be reclaimed and yet is not a leak.

AUTHOR

ara [dot] t [dot] howard [at] gmail [dot] com

enjoy!

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![ara\_howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d9b06d/32.png) [@ara\_howard](https://www.ruby-forum.com/u/ara_howard)\
**Post date:** [January 9, 2008, 8:28pm UTC](https://www.ruby-forum.com/t/dike-0-0-4/125507/2 "2008-01-09T20:28:11Z")

</div>

On Jan 9, 2008, at 10:51 , ara howard wrote:

> ```
> loop do
> Leaks << Leak.new('leak' * 1024)
> Dike.finger
> sleep 1
> end
> 
> ```

Shouldn’t that be DutchBoy instead of Dike?

😛

---

<div class="post-metadata">

**Author:** ![ara\_howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d9b06d/32.png) [@ara\_howard](https://www.ruby-forum.com/u/ara_howard)\
**Post date:** [January 9, 2008, 8:34pm UTC](https://www.ruby-forum.com/t/dike-0-0-4/125507/3 "2008-01-09T20:34:38Z")

</div>

On Jan 9, 2008, at 12:27 PM, Ryan D. wrote:

> Shouldn’t that be DutchBoy instead of Dike?

it’s a library for the ladies 😉

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![ara\_howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d9b06d/32.png) [@ara\_howard](https://www.ruby-forum.com/u/ara_howard)\
**Post date:** [January 11, 2008, 5:35pm UTC](https://www.ruby-forum.com/t/dike-0-0-4/125507/4 "2008-01-11T17:35:44Z")

</div>

On 9 ene, 19:51, ara howard [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> # cfp:~ > cat ./log/dike/0
> ---
> - class: String
> count: 90769
> trace: []
> - class: Array
> count: 18931
> trace: []
> 
> ```

So how do you interpret these kinds of results with empty stack  
traces? So you know a bunch of String and Array objects are being  
created and aren’t going to be collected, at least at the point where  
you called Dike.finger, but you don’t know where they were created  
(admittedly, there are so many of them it probably wouldn’t help you  
much to know that they were being created “all over the place”).

Cheers,  
Wincent

---

<div class="post-metadata">

**Author:** ![ara\_howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d9b06d/32.png) [@ara\_howard](https://www.ruby-forum.com/u/ara_howard)\
**Post date:** [January 11, 2008, 5:59pm UTC](https://www.ruby-forum.com/t/dike-0-0-4/125507/5 "2008-01-11T17:59:59Z")

</div>

On Jan 11, 2008, at 9:35 AM, Wincent C. wrote:

> So how do you interpret these kinds of results with empty stack  
> traces? So you know a bunch of String and Array objects are being  
> created and aren’t going to be collected, at least at the point where  
> you called Dike.finger, but you don’t know where they were created  
> (admittedly, there are so many of them it probably wouldn’t help you  
> much to know that they were being created “all over the place”).

dike does what it can to track the object lifecycle, but certain  
things cannot be traced to a specific file:line. for instance

string = “literal”

array = [:literal]

does not trigger Class.new, Class.allocate, or Object#initialze to be  
triggered (in ruby) and this is the main mechanism for dike to track  
objects. dike tracks objects per class per stacktrace so it knows  
about the Leak objects coming from file a.rb, line 42, for example.  
so certain objects cannot be tracked. it’s a good reason to prefer  
Hash.new over {} though 😉 if they could be tracked it wouldn’t be  
an issue that they were ‘all over the place’ since the dike  
commandline tool provides a way to compare one dump to the next,  
showing only leaks in the output and ignoring those entries that are  
not leaks.

in the end it’s a limitation of dike. nonetheless, i’ve been able to  
reduce memory leaks in many rails apps in 30 minutes of work using  
dike.rb, so it is not without it’s usefulness. also, note that even  
a c instrumented object cycle tracker will fail to detect things like

void \*leak(){ return malloc(42) }

in a c extension - all the tools have their limits. for ruby i think  
starting with something like dike.rb, moving up to something like  
bleakhouse, with it’s custom ruby, and finally moving on to c only  
tools is a logical process to follow.

another very important technique is, as much as possible, to use  
binary search on your code you determine leaks: hack your code so the  
back 50% of it doesn’t run - test for the leak - then adjust up or  
down based on what you find. this along can narrow down on the  
leaking bits of code _very_ quickly. then a tool like dike.rb can  
identify the exact lines.

it all starts feeling like we are back to c++ doesn’t it 😉

cheers
