Why isn't this simple class garbage collected in Ruby console?
It seems this was already answered in another question
Pry stores the output of the last 100 commands and thus the object can't actually be garbage collected.
Anonymous modules and classes garbage collection in Ruby
ObjectSpace.garbage_collect does not mean that a garbage collection will be performed. It's only a hint to the Ruby runtime.
On some platforms it isn't even possible for the Ruby runtime to initiate a garbage collection, because the garbage collector isn't even part of the Ruby runtime, e.g on JRuby or IronRuby.
In general, the Ruby runtime will decide on its own when it will perform a garbage collection. Usually, that's when it runs out of memory. 100000 modules aren't that big, so there's simply no need to perform a GC cycle.
Also, most Ruby implementations will never release memory back to the OS, even after a GC cycle.
So, just the fact that the
ObjectSpace doesn't shrink doesn't necessarily mean that you have memory leak. It could simply mean that the Ruby runtime didn't yet deem it necessary to run a GC cycle.
Also note that if you run this code from IRb, Pry, an IDE console or some other non-standard environment, then it may be the case that those hold on to some of those modules. For example, Pry stores the results of the last 100 commands in a history array. (Try evaluating
_out_ in Pry, after entering your example program.)
How to destroy Ruby object?
Other than hacking the underlying C code, no. Garbage collection is managed by the runtime so you don't have to worry about it. Here is a decent reference on the algorithm in Ruby 2.0.
Once you have no more references to the object in memory, the garbage collector will go to work. You should be fine.
Sizes of object for garbage collector
The guy who said that you should benchmark it is right -- GC is a complex issue and it's hard to give a 100% correct answer.
Also, it depends on the implementation being used. In JRuby, it's the JVM doing the work. In MRI, it's a mark-and-sweep GC.
On the case of MRI, it works more or less like this: each time that the Ruby interpreter needs more memory, it runs the GC to try and free it. If there isn't enough memory, it'll allocate more. And the GC decides that an object is ok to be freed ("mark" it) when there aren't references to it.
The only advice I can give you is to avoid using lots of objects that can't be garbage collected. For example, if you're building an array of strings (their size isn't important), you should see performance degradation much more rapidly than if you created a big string concatenating each of the smaller ones.
This is because in the latter the GC can destroy the small strings after they're used, while in the former the array is always maintaining a reference to each one of them.
EDIT: Of course, this assumes that the cost of maintaining them in memory is bigger than the slowdown of dealing with the "big string". In some cases, it's better to have small strings and then concatenate they all -- resulting in a single slow operation. Again, these are just examples without benchmarks, don't take them very seriously.