Singletons as globals and GC

B

Ben Giddings

Although Ruby allows the use of global variables, I still prefer not to
use them. I am wary that someone else might have chosen the same
variable name as me, and besides, they just don't feel properly OO.
Singletons seem like the best solution to this problem, but I'm
concerned about garbage collection.

Say I have two classes that each do a lot of work. I instantiate one,
do a bunch of calculations and return a result. I then instantiate a
second class and do a bunch more work on that result. Say both classes
want to use this global / singleton, and want to make sure that it
doesn't get garbage collected between calls, what's the best way to do
this?

Example code:

class Stats
include Singleton
def initialize
@count = 0
end

def sawAnother
@count += 1
end
end

class Worker1
def doStuff
@stats = Stats.instance
...
end
end

class Worker2
def doOtherStuff
@stats = Stats.instance
...
end

def showResult
@stats.dumpStats
end
end

w1 = Worker1.new
w1.doStuff

w2 = Worker2.new
w2.doStuff
w2.showResult

What I want to avoid is having the Stats singleton get garbage
collected between calls to w1.doStuff and the creation of Worker2.new.
Any comments?

Ben
 
Y

Yukihiro Matsumoto

Hi,

In message "Singletons as globals and GC"

|w1 = Worker1.new
|w1.doStuff
|
|w2 = Worker2.new
|w2.doStuff
|w2.showResult
|
|What I want to avoid is having the Stats singleton get garbage
|collected between calls to w1.doStuff and the creation of Worker2.new.
|Any comments?

I don't know what you meant. If w1 is referenced from somewhere, w1
will not be garbage-collected.

matz.
 
S

Sascha Dördelmann

Ben Giddings said:
Although Ruby allows the use of global variables, I still prefer not to
use them. I am wary that someone else might have chosen the same
variable name as me, and besides, they just don't feel properly OO.
Singletons seem like the best solution to this problem, but I'm
concerned about garbage collection.

Say I have two classes that each do a lot of work. I instantiate one,
do a bunch of calculations and return a result. I then instantiate a
second class and do a bunch more work on that result. Say both classes
want to use this global / singleton, and want to make sure that it
doesn't get garbage collected between calls, what's the best way to do
this?

Classes are global and a singleton instance will be referenced by a
static variable/class variable of the singleton class. (See the design
patterns book by the GOF.) I can't see a problem for the GC there.
It's easy to test: Invoke the GC within your example. Does it still
work?

I recommend that you try to avoid using global access paths to
singletons whenever you design a big application. The application will
be easier to maintain if you identify components and make each
component access global objects via access paths local to that
component. You could use another singleton to do so , e. g.
MyComponentGlobals.instance.getStats.

You can find some discussions about the problems singletons might
introduce here:
- Search for the thread "Q: Singleton" in comp.lang.smalltalk
- Read http://c2.com/cgi/wiki?SingletonPattern (and follow some of the
links)

Cheers
Sascha
 
B

Ben Giddings

|w1 = Worker1.new
|w1.doStuff
|
|w2 = Worker2.new
|w2.doStuff
|w2.showResult

I don't know what you meant. If w1 is referenced from somewhere, w1
will not be garbage-collected.

Sorry I wasn't more clear. I meant to give a case where there are no more
references to w1 after the doStuff method is called. It's not w1 or w2 being
garbage-collected that I'm worried about, it's the "@stats" variable that
they both use, which is a singleton instance.

What I'd like is a way to make sure that the instance variable of a singleton
object I create in the first class still exists by the time the second class
tries to create it.

class Worker1
def doStuff
@stats = Stats.instance # The instance of the stats singleton is created
...
end
end

class Worker2
def doOtherStuff
@stats = Stats.instance # It still exists here
...
end

def showResult
@stats.dumpStats
end
end

Worker1.new.doStuff

# Here is where I don't want the stats singleton to be GC'd

w = Worker2.new
w.doOtherStuff
w.showResult

I guess what I'm looking for is a way to create a hidden global variable when
a singleton instance is created, in a way that there is no danger of name
clashes. Because there would always be at least one reference to the
singleton, it would only get GC'd at the end of the program's lifetime, and
this would guarantee it would only ever be created once.

Some examples of where this would be useful:
* There are a large number of unrelated classes which should dump debugging
info into a log. You want a new log each time the program is run, and you
want to replace the old log. So you create / truncate the file when the
first class needs to log something, and each other class appends to the log,
until the end of the program.
* The act of creating an instance of a class is long and time-consuming, so
you only want it to happen once for the entire lifetime of the program,
whether it's used frequently or not

I hope I explained it better this time.

Ben
 
T

ts

B> class Worker1
B> def doStuff
B> @stats = Stats.instance # The instance of the stats singleton is created

svg% cat b.rb
#!/usr/bin/ruby
require 'singleton'
class Stats
include Singleton
end
p Stats.instance
Stats.instance_eval { p @__instance__}
svg%

svg% b.rb
#<Stats:0x40092d60>
#<Stats:0x40092d60>
svg%


the instance is a class instance variable, because the class Stats will be
not removed, the instance will be marked when the GC run


Guy Decoux
 
B

Ben Giddings

the instance is a class instance variable, because the class Stats will be
not removed, the instance will be marked when the GC run

Ah, how cool. I have never (knowingly) encountered a class instance variable
before, especially not one that contained an instance of itself. Now that I
take a closer look it all makes good sense, and does exactly what I want.
When I found out that classes in ruby are instances of the "Class" type, I
knew that would add all kinds of flexibility, but I didn't anticipate this
use.

Thanks,

Ben
 
S

Sascha Dördelmann

Ben Giddings said:
Ah, how cool. I have never (knowingly) encountered a class instance variable
before, especially not one that contained an instance of itself. Now that I
take a closer look it all makes good sense, and does exactly what I want.
When I found out that classes in ruby are instances of the "Class" type, I
knew that would add all kinds of flexibility, but I didn't anticipate this
use.

Just another warning. I don't know how to control the instance
creation time of singletons in Ruby. I would guess it's lazy
initialisation. This could introduce problems when comparing memory
snapshots. You gonna get differences where you don't expect them.

So although you are happy that the GC don't kill your singleton, I
would like to know: Is there a standard way to remove a singleton in
Ruby?

(---- Off topic remark: ---- snip >-----
I've seen some discussion about Ruby IDEs stating that you'll need an
image based ruby IDE to implement a powerful debugging environment. In
an image based IDE all objects building the IDE could be made
persistent. You can store the complete state of the IDE including
windows and running processes. Think about storing the state of IRB
and you have an image based system.

Singletons will cause problems in such an image based system:
http://c2.com/cgi/wiki?SmalltalkSingletonProblem

Not only IDEs benefit from storing the state of processes, a PC with
powermanagement or a database needs to store the state of running
processes, too.
------)

Cheers
Sascha
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,108
Latest member
AlbertEste
Top