System stack error in ObjectSpace.each_object

Hey guys, I’m just starting to mess around with metaprogramming in Ruby,
so I was just having a bit of fun and trying to make a script that would
allow for creating a ‘leader’ object in a class, and then when that
object is sent a message, all other objects of some subordinate class
would respond to the same message.

So the script I wrote is here:
https://github.com/luke-gru/lemmings/blob/master/leader.rb

On line 52, I ran into this issue:

def get_other_objects(subord_class)
obj_ary = []
ObjectSpace.each_object(subord_class) do |o|
obj_ary.push(o) unless o.leader # here
end
obj_ary
end

If I don’t have the ‘unless o.leader’ expression modifier, it pushes
like a million of the ‘leader’ objects and raises a SystemStackError.

I have no idea why, and would really appreciate an answer.

Thanks,

-Luke

On Sun, Jul 31, 2011 at 4:29 PM, luke gruber [email protected] wrote:

I have no idea why, and would really appreciate an answer.

Thanks,

-Luke


Posted via http://www.ruby-forum.com/.

When I ran your script, I didn’t get that error. I got this output:

Test
true
#Test:0x0ac544
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys
hey guys

#Test:0x0ac7ec jumps: ‘look at me!’

#Test:0x0ac5bc jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac60c jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac620 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac634 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac65c jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac6c0 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac710 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac738 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac74c jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac760 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac788 jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac7ec jumps: ‘Ahhhhhhhhh!’
#Test:0x0ac544 jumps: ‘Ahhhhhhhhh!’

#Test:0x0ac7ec
#Test:0x0ac788
ouch
ouch
ouch
ouch
ouch
ouch
ouch
ouch
ouch
ouch
ouch
ouch

Typically, SystemStackError is due to recursing for too long, perhaps I
have
more memory than you, or perhaps the Ruby I’m using (1.9.2-p180) is less
memory intensive than the one you’re using. Anyway, it should give you a
message with more information and a stack trace / line number that tells
you
where to begin looking.

Typically, SystemStackError is due to recursing for too long, perhaps I
have
more memory than you, or perhaps the Ruby I’m using (1.9.2-p180) is less
memory intensive than the one you’re using.

Yeah, I’m running the same Ruby version and I have 4 gb of ram, not sure
why I get this error. Just to be sure, the script in the file
(unmodified) gives me no errors, but when I remove ‘unless o.leader’ on
line 51, that’s when I run into this problem.

Anyway, thanks for checking.

-Luke

This looks to me like an abuse of ObjectSpace.

If you need to keep track of all the objects of class Foo, then it would
be better to make some sort of container which keeps track of them
explicitly.

ObjectSpace is (a) inefficient, because it scans every object in the
system, and (b) unreliable, because it may show you objects which should
have died, but some reference is being held somewhere.

ObjectSpace is really just a debugging tool.

Also, finalizers are also extremely difficult to work with. There is
almost never a good case for using them. You should consider them part
of the internals of ruby (so that, for example, when an IO object gets
garbage-collected then the underlying file descriptor gets closed)

Regards,

Brian.

On Mon, Aug 1, 2011 at 3:56 AM, luke gruber [email protected] wrote:

Anyway, thanks for checking.
I can reproduce


/c/Temp/leader.rb:41:in each' /c/Temp/leader.rb:41:in block (4 levels) in show_leadership’
/c/Temp/leader.rb:41:in block (3 levels) in show_leadership' /c/Temp/leader.rb:41:in each’
/c/Temp/leader.rb:41:in `block (4 levels) in show_leadership’

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension
libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Aborted (core dumped)
09:05:22 ~$ ruby19 -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [i386-cygwin]

I assume you created some weird kind of recursion via
define_finalizer. I’m not really sure what’s going on. Can you
explain what your code is supposed to do?

Kind regards

robert

I assume you created some weird kind of recursion via
define_finalizer. I’m not really sure what’s going on. Can you
explain what your code is supposed to do?

robert

Yeah, it was just for fun and to learn some of these metaprogramming
methods, but what I was meaning to do was to be able to make a ‘leader’
object of, say, class Foo. Upon choosing the leader object, you have to
choose a subordinate class to lead (which could be the same class as the
leader object, ie: Foo.

Basically the implementation was to take all the objects of the
subordinate class, then override all of the instance methods in the
leader object’s class by putting new methods in the leader’s singleton
class with the same name as the instance methods in the leader’s class.
Every time these new ‘leader’ methods are called (ie: the leader
responds to a method that’s defined in the leader’s own class), it sends
the same method (with the same args &block) to all the subordinate
objects.

Anyway, I’m just having fun and I know playing with ObjectSpace can lead
to some weird errors, but this error seems to be consistent enough in
that I kept on running into it until I added that statement modifier.

Thanks for checking it out.

===========================
1)

If you need to keep track of all the objects of class Foo, then it would
be better to make some sort of container which keeps track of them
explicitly.

ObjectSpace is (a) inefficient, because it scans every object in the
system, and (b) unreliable, because it may show you objects which should
have died, but some reference is being held somewhere.

Brian.

  1. For the container idea, how would you go about doing this?
  2. As for ObjectSpace returning dead objects, is there a way to force GC
    during runtime? Also, does taking all variables that point to an object
    and pointing them to nil effectively dangle an object like this?

Thanks Robert and Brian,

-Luke

luke gruber wrote in post #1014312:

I assume you created some weird kind of recursion via
define_finalizer. I’m not really sure what’s going on. Can you
explain what your code is supposed to do?

Yeah, it was just for fun and to learn some of these metaprogramming
methods, but what I was meaning to do was to be able to make a ‘leader’
object of, say, class Foo. Upon choosing the leader object, you have to
choose a subordinate class to lead (which could be the same class as the
leader object, ie: Foo.

Basically the implementation was to take all the objects of the
subordinate class, then override all of the instance methods in the
leader object’s class by putting new methods in the leader’s singleton
class with the same name as the instance methods in the leader’s class.
Every time these new ‘leader’ methods are called (ie: the leader
responds to a method that’s defined in the leader’s own class), it sends
the same method (with the same args &block) to all the subordinate
objects.

Not sure what this is supposed to do but I would always make the
connection between those objects explicit. And I would separate the
leading from determining the set of instances to lead. Here’s one way

class Leader < BasicObject
def lead(source)
@objs = source
end

def method_missing(*a,&b)
@objs.map {|o| o.send(*a,&b)}
end
end

class Module
Source = Struct.new :cl do
include Enumerable

def each(&b)
  return to_enum(:each) unless b
  ObjectSpace.each_object(cl, &b)
  self
end

end

def lemmings
Source.new self
end
end

l = Leader.new
l.lead Hash.lemmings

p l.size

Kind regards

robert

On Tue, Aug 2, 2011 at 3:12 AM, luke gruber [email protected] wrote:

  1. For the container idea, how would you go about doing this?

In the initialize (or new) method of Foo, store self in a container
(an array on Foo, or another class).
But take into account that this means that all instances of Foo will
have an alive reference, so they will never be garbage collected.
Something like:

ruby-1.8.7-p334 :003 > class FooCollection
ruby-1.8.7-p334 :004?> class << self
ruby-1.8.7-p334 :005?> attr_reader :collection
ruby-1.8.7-p334 :006?> def << item
ruby-1.8.7-p334 :007?> (@collection ||= []) << item
ruby-1.8.7-p334 :008?> end
ruby-1.8.7-p334 :009?> end
ruby-1.8.7-p334 :010?> end
=> nil
ruby-1.8.7-p334 :015 > class Foo
ruby-1.8.7-p334 :016?> def initialize
ruby-1.8.7-p334 :017?> FooCollection << self
ruby-1.8.7-p334 :018?> end
ruby-1.8.7-p334 :019?> end
=> nil
ruby-1.8.7-p334 :020 > a = Foo.new
=> #Foo:0xb70d9c80
ruby-1.8.7-p334 :021 > b = Foo.new
=> #Foo:0xb70d7dcc
ruby-1.8.7-p334 :022 > FooCollection
=> FooCollection
ruby-1.8.7-p334 :023 > FooCollection.collection
=> [#Foo:0xb70d9c80, #Foo:0xb70d7dcc]

Take note that even if a and b go out of scope, the Foo instances they
referenced will never be GCed, because they are referenced by the
FooCollection.collection array.

Jesus.

luke gruber wrote in post #1014312:

  1. For the container idea, how would you go about doing this?

Others have answered this already. (There’s weakref if you really need a
container which doesn’t prevent garbage collection, but I’ve never had
to use it)

  1. As for ObjectSpace returning dead objects, is there a way to force GC
    during runtime?

You can force garbage collection, but the issue is rather that the
garbage collector is conservative; any bit of junk sitting on the stack
which looks like it might be a reference to an object is treated as if
it is, just to be on the safe side. This means that some objects which
really could be garbage-collected, aren’t.

You can write some simple test programs using ObjectSpace to count the
number of objects of each class, create some and drop the refs, then run
GC.start, then count them again. It’s not unusual to see one or two
objects left in a particular class, even though there are no live refs.

Also, does taking all variables that point to an object
and pointing them to nil effectively dangle an object like this?

Explicitly destroying all references to an object will normally make it
eligible for garbage collection: it’s a mark-and-sweep collector, so the
object won’t be found during the mark phase. But as I say, a few objects
may be considered live when technically they aren’t.

Something like:
ruby-1.8.7-p334 :003 > class FooCollection

Jesus.

That’s cool, I like the way the class is effectively just that, a set
that’s keeping track of the objects.

Thanks.

I would separate the leading from determining the set of instances to lead.

robert

I don’t quite understand your example code.

class Module
Source = Struct.new :cl do
include Enumerable

def each(&b)
return to_enum(:each) unless b
ObjectSpace.each_object(cl, &b)

ObjectSpace.each_object takes, as its first argument, a module. I
thought
:cl was an instance variable of instances of the Source class. I don’t
know much about structs, so I’d love an explanation.

Thanks Robert.

And Bryan, thanks for the explanations. I checked out weakref and it
looks
kinda cool. Although, yeah, can’t imagine using it.

-Luke

On Wed, Aug 3, 2011 at 3:54 AM, luke gruber [email protected] wrote:

I would separate the leading from determining the set of instances to lead.

I don’t quite understand your example code.

There are two parts:

  1. The method call propagation is done by instances of class Leader
    which inherits BasicObject in order to have the minimum set of
    predefined methods. A Leader takes an Enumerable as source for
    instances to delegate to, which means you can stuff in anything which
    is Enumerable (e.g. Array, Set).

  2. Then I created a class Source which is also Enumerable and happens
    to look into ObjectSpace whenever someone wants to iterate via #each.
    So, ObjectSpace would be only one way to look for instances.

class Module
Source = Struct.new :cl do
include Enumerable

def each(&b)
return to_enum(:each) unless b
ObjectSpace.each_object(cl, &b)

ObjectSpace.each_object takes, as its first argument, a module.

… or a class. Correct.

I thought
:cl was an instance variable of instances of the Source class. I don’t
know much about structs, so I’d love an explanation.

In the example “cl” is a member of the Struct which means there is a
pair of accessor methods, so “cl” really is a call to the getter. And
the getter is set to “self” in Module#lemmings (which is an instance
method of all modules and classes).

Struct is really a handy way to quickly create a class with a few
properties which also gives you #hash and #eql?. You can read more at
http://blog.rubybestpractices.com/posts/rklemme/017-Struct.html

Kind regards

robert

There are two parts:

In the example “cl” is a member of the Struct which means there is a
pair of accessor methods, so “cl” really is a call to the getter. And
the getter is set to “self” in Module#lemmings (which is an instance
method of all modules and classes).

robert

I’m an idiot, I just forgot that instance methods defined in class
Module are effectively singleton methods for all classes and modules (or
if they aren’t, please let me know!).

Another question: is there a reason you explicity include enumerable,
because I think structs include enumerable by default?

Also, the member of a struct is set to ‘self’ by default?

Thanks again, I’m gonna look into your blog post.

-Luke

I read your post, Structs now make MUCH more sense, thanks. Should
have read before I posted above.

class Module
Source = Struct.new :cl do

So this is effectively creating a Source class that inherits from class
Struct and takes one argument to its constructor (initialize method)…

But my question still stands on whether or not the ‘include Enumerable’
was just for clarification and to be explicit, because unless I’m wrong
class Struct includes Enumerable and Source is a child of class Struct,
inheriting #each.

Thanks for your patience, your blog looks like it’s full of info. I’ve
gotta catch up on all the holes in my Ruby knowledge :slight_smile:

-Luke

On Wed, Aug 3, 2011 at 11:43 PM, luke gruber [email protected] wrote:

I read your post, Structs now make MUCH more sense, thanks. Should
have read before I posted above.

class Module
Source = Struct.new :cl do

So this is effectively creating a Source class that inherits from class
Struct and takes one argument to its constructor (initialize method)…

Plus, you will have one pair of accessors for “cl” and a few more
things (e.g. access via [] like for a Hash).

But my question still stands on whether or not the ‘include Enumerable’
was just for clarification and to be explicit, because unless I’m wrong
class Struct includes Enumerable and Source is a child of class Struct,
inheriting #each.

You’re absolutely right. I wanted to make it explicit but of course
it’s superfluous in this case. Should have added a comment. Sorry
for the confusion.

Thanks for your patience, your blog looks like it’s full of info. I’ve
gotta catch up on all the holes in my Ruby knowledge :slight_smile:

Thank you for the feedback! And I need to catch up writing… Oh well.

Kind regards

robert