Memory leak in ruby code


#1

Hi,

I’m trying to write a code that’d inspect my method calls for any
memory leaks. You can find my code at http://pastie.caboo.se/49859

In my method, I have

def leaker
“hello”
end

Here, as per my code, the string “hello” is caught as a leak. Could
someone tell me if I’m doing it the right way ?

Thanks,
Pratik


#2

So my first question is this: why are you doing this? Ruby’s garbage
collector is perfectly capable of finding and preventing REAL memory
leaks.

What you have here is not a memory leak detector, but an “objects have
been
created” detector. “hello” is then obviously caught as a new object
created,
and as Ruby returns the result of the last statement of a method, it is
not
yet out of scope until the program quits, in your case.

Jason


#3

On 3/27/07, Jason R. removed_email_address@domain.invalid wrote:

So my first question is this: why are you doing this? Ruby’s garbage
collector is perfectly capable of finding and preventing REAL memory leaks.

What you have here is not a memory leak detector, but an “objects have been
created” detector. “hello” is then obviously caught as a new object created,
and as Ruby returns the result of the last statement of a method, it is not
yet out of scope until the program quits, in your case.

There’s also the problem that he’s trying to detect surviving objects
by comparing object_ids before and after GC, there’s no guarantee that
an object_id of a gc’d object won’t be reused. Object_id’s only need
to be unique among LIVE objects.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#4

On Wed, Mar 28, 2007 at 07:46:43PM +0900, Pratik wrote:

Thanks for your replies. I’ve modified the code a little so that my
string “hello” is not the last statement. And also, it is used in
“puts”. Even when it’s out of scope, it’s not being free.

Objects are not freed when they go out of scope. Objects are freed when
the
garbage collector runs, and notices that no outside references point to
these objects. (This is “mark and sweep garbage collection”)

You can force this to happen using GC.start, if you wish to play around
with
the internals.

Doing it other ways (e.g. reference counting) is expensive and
error-prone.
I have a vague recollection that Python does it this way though.


#5

I’ve already called GC.start and yet some objects are not being freed.
However, I’m still uncertain about memory leaks in ruby code and
looking for an example of any such case.

Thanks,
Pratik

On 3/28/07, Brian C. removed_email_address@domain.invalid wrote:

the internals.

Doing it other ways (e.g. reference counting) is expensive and error-prone.
I have a vague recollection that Python does it this way though.


rm -rf / 2>/dev/null - http://null.in

Dont judge those who try and fail, judge those who fail to try…


#6

Hi,

Thanks for your replies. I’ve modified the code a little so that my
string “hello” is not the last statement. And also, it is used in
“puts”. Even when it’s out of scope, it’s not being free.

http://pastie.caboo.se/50041

Jason : Why I’m doin this, frankly speaking, the concept of memory
leaks in ruby code is still not very clear to me. I came across
http://scottstuff.net/blog/articles/2006/08/17/memory-leak-profiling-with-rails

  • which checks for common objects within 10 seconds interval. So I
    wrote a lil piece of code myself to see if any objects created in a
    method call, are getting removed or not when it’s out of scope.

I’d like to see if someone can point me to an example of memory leak
in ruby code. Or lemme know how to detect proper memory leaks.

Thanks!
Pratik

On 3/27/07, Rick DeNatale removed_email_address@domain.invalid wrote:

by comparing object_ids before and after GC, there’s no guarantee that
an object_id of a gc’d object won’t be reused. Object_id’s only need
to be unique among LIVE objects.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


rm -rf / 2>/dev/null - http://null.in

Dont judge those who try and fail, judge those who fail to try…


#7

On 28.03.2007 23:41, Pratik wrote:

I’ve already called GC.start and yet some objects are not being freed.
However, I’m still uncertain about memory leaks in ruby code and
looking for an example of any such case.

A memory leak comes into existence when some piece of code holds longer
onto an instance than necessary / intended. Look at this:

class Foo
@instances = []

def self.register(obj)
@instances << obj
end

def initialize
Foo.register(self)
end
end

Instances register with their class but never deregister - so they can
never be collected and use up memory. My guess would be that you’ll
have a hard time writing a program that is able to track these without
actually running the code.

Kind regards

robert


#8

Pratik, the only real memory leaks you will see in a Ruby program is
when a
program keeps a hold of data indefinitely. This usually manifests itself
in
long running programs with caches or when it just needs to keep info in
memory. When you’re dealing with programs that run for days, weeks, or
months at a time, no matter what language you are in you need to be very
careful what objects are kept around and for how long.

Otherwise, it’s just spilt milk.

Jason


#9

The memory leak is a situation where programmer undeliberately keep
some objects in memory but not aware of, usually by poor
implementation of object destructors.
The repercussion of such is that some memory is never released and can
be seen as memory consumption build up with no reasonable explanation.

The above example is not such.

The languages with garbage collectors are less exposed to memory leaks
in a general sense.
If you keep a reference to some object is something you do on
purpose.

To be truly onset the garbage collector is also o piece of code
written by humans ;-).


#10

On Fri, Mar 30, 2007 at 04:10:04PM +0900, Robert K. wrote:

never be collected and use up memory. My guess would be that you’ll
have a hard time writing a program that is able to track these without
actually running the code.

IMO, that’s not a memory leak, that’s correct behaviour. You created
some
objects and purposely held on to references to them. At any point later
in
the code someone might do Foo.class_eval { @instances.[n] }

My definition of a memory leak would be when memory has been allocated
but
there are no remaining references to it available anywhere, meaning
that
it has been effectively lost and can never be freed.

This shouldn’t/can’t happen in pure Ruby code. But it can certainly
happen
in C extensions, where memory has been malloc()d but the pointer
forgotten
about.

Regards,

Brian.


#11

In message removed_email_address@domain.invalid, dima
removed_email_address@domain.invalid writes

If you keep a reference to some object is something you do on
purpose.

Unless there is an error in your logic. Perhaps you forgot to clear the
reference(s) to the object when you were finished with it? Perhaps the
design changed and you forgot to clear the reference, or forgot to call
a method that cleared the reference.

No different to a memory leak in a non-garbage collected language.
Engineers don’t put errors in programs deliberately (well, if you’ve got
one, you need to sack them), they happen by mistake, design error,
tiredness, Friday afternoons, etc. Thats life, stuff happens.

That is why since Java came on the scene companies like Sitraka (with
JProbe in 1996) and many others since have produced tools to detect such
situations. Its also why we created Ruby Memory Validator, because such
problems do exist for some applications.

http://www.softwareverify.com/ruby/memory/index.html

The main problem with leaks in garbage collected programs is that by
their very nature (an unwanted reference is held) they are harder to
detect than for non-garbage collected programs.

The statement you write above makes me think you have not truly
experienced a memory leak situation in a GC’d application (regardless of
language - the principles remain the same).

I mention Sitraka as they were the first company I am aware of that
released a commercial tool for this task. They also published an article
in Dr Dobbs detailing their position on this area and the terms they
used. They called an unwanted object a “loiterer” if I recall correctly.
There were three types:

o Unwanted object references held longer than necessary by accident (the
typical memory leak scenario). This reference could be stored in a
static data member (class member) or in a dynamic data member (instance
member)

o Temporary object on stack held for longer than necessary, preventing
potentially large object trees from being collected

someFunc()
{
obj = createALargeNumerOfObjectsAndGiveMeTheRoot();

    doSomeWork(obj);

    doSomeOtherWorkThatCouldDoWithMemoryReclaim();

}

obj could be reclaimed after doSomeWork() (assuming the stack ref is the
only reference to it) but because it is on the stack it can’t be. A
better way to do this would be to create a local scope for it (yes,
there are other variantions, this is just to demo the point)

someFunc()
{
{
obj = createALargeNumerOfObjectsAndGiveMeTheRoot();

            doSomeWork(obj);
    }

    doSomeOtherWorkThatCouldDoWithMemoryReclaim();

}

o Some other case I can’t recall right now (sorry I have a horrible cold
and don’t feel so good, so memory not working so good…). I’m pretty
sure there was a third case, but it eludes me. Sorry.

It quite interesting watching the Ruby community have the same
discussions (and same misconceptions) about memory as happened in the
Java community over a decade ago.

I’ve found a reference to Sitraka’s work here: Its a powerpoint
presentation. For all of you that think memory leaks can’t happen in a
GC’d environment please take a look. Its a not a leak in the terms of a
C memory leak, but you are still chewing through memory.

These are different presentations, found using a simple Google search:

http://www.java-forum-stuttgart.de/jfs/2001/folien/C2.ppt
http://java.quest.com/JUG/meetings/presentations/sep02/JUG%20Sept%202002.
PPT

I hope you find them interesting. They apply to Ruby just as much as
they do to Java.

Stephen


#12

On 31.03.2007 23:39, Stephen K. wrote:

I mention Sitraka as they were the first company I am aware of that
released a commercial tool for this task. They also published an article
in Dr Dobbs detailing their position on this area and the terms they
used. They called an unwanted object a “loiterer” if I recall correctly.
There were three types:

I believe OptimizeIt is also around for pretty long time. I knew it
before JProbe but that doesn’t mean anything.

Kind regards

robert


#13

On 31.03.2007 10:24, Brian C. wrote:

never be collected and use up memory. My guess would be that you’ll
have a hard time writing a program that is able to track these without
actually running the code.

IMO, that’s not a memory leak, that’s correct behaviour.

From the interpreter’s point of view.

You created some
objects and purposely held on to references to them. At any point later in
the code someone might do Foo.class_eval { @instances.[n] }

While this might actually happen, the issue I tried to convey is that no
instances of class Foo will never be collected because @instances holds
on to all of them. If this is intended then this is of course not a
leak but as my explanation should have made clear this was not intended
in the example. I probably should have been clearer about this.

My definition of a memory leak would be when memory has been allocated but
there are no remaining references to it available anywhere, meaning that
it has been effectively lost and can never be freed.

This cannot happen in Ruby and Java. In these languages the term
“memory leak” is actually used for memory that cannot be freed because
something holds on to it longer than intended.

This shouldn’t/can’t happen in pure Ruby code. But it can certainly happen
in C extensions, where memory has been malloc()d but the pointer forgotten
about.

That’s another story. But I think the OP was looking for memory leaks
in Ruby code.

Kind regards

robert


#14

In message removed_email_address@domain.invalid, Robert K.
removed_email_address@domain.invalid writes

I believe OptimizeIt is also around for pretty long time. I knew it
before JProbe but that doesn’t mean anything.

OptimizeIt was also an early arrival. Any tool launched in 1996 was on
the bleeding edge. I looked at Optimizeit back then and hated its UI. So
much useful information was either missing or hidden behind an awful UI.

Borland appear to be the current owner of OptimizeIt, which appears to
be part of the JBuilder product.

Stephen


#15

On 04.04.2007 01:33, Stephen K. wrote:

In message removed_email_address@domain.invalid, Robert K.
removed_email_address@domain.invalid writes

I believe OptimizeIt is also around for pretty long time. I knew it
before JProbe but that doesn’t mean anything.

OptimizeIt was also an early arrival. Any tool launched in 1996 was on
the bleeding edge. I looked at Optimizeit back then and hated its UI. So
much useful information was either missing or hidden behind an awful UI.

Interesting point: we bought OptimizeIT few years ago because we
disliked JProbe’s UI and performance. :slight_smile:

Borland appear to be the current owner of OptimizeIt, which appears to
be part of the JBuilder product.

Correct.

robert