Does Ruby allocate everything on the heap or are there any instances where something is stored on the stack? I'm under the impression that all variables are essentially on the stack and contain a transparent reference to an object on the heap. Am I correct in this thinking? Is this implementation specific?
Also, if it is the case that variables are allocated on the stack and merely contain hidden pointers, how many bytes do the variables themselves (disregarding the objects they point to) consume?
Edit:
This question was asked because I was trying to figure out whether a fiber's 4kB stack limit would be an issue in this question. It seems as though (with MRI 1.9.3) that each variable itself consumes one byte and there's a slight overhead associated with the fiber which reduces the available stack size by a few bytes.
This code will fail on the 4,045th iteration:
count = 0
loop do
count += 1
puts count
varlist = String.new
count.times do |i|
varlist += "a#{i} = 1\n"
end
s = "fiber = Fiber.new do \n #{varlist} \n end \n fiber.resume"
eval(s)
end
It depends on the Ruby implementation.
For example, Ruby 2.0 MRI (the typical one on most systems) stores all its objects in heaps. Small objects such as short strings can fit entirely in the heaps. For large objects, Ruby will malloc extra memory outside of the heaps.
See "MRI Memory Allocation - A Primer For Developers" and "Demystifying the Ruby GC"
Here's "Understanding How Ruby Stores Objects In Memory" which has a great, longer, description:
Another good source is "How Ruby Manages Memory and Garbage Collection", which links to slides at "Garbage Collection Slides from LA Ruby Conference".
Fibers
Fibers are special in Ruby because each fiber gets its own small stack.
You may be interested in a long-running feature request for dynamic fiber stack sizing.
If you are more interested in a real-world solution, the feature request author recommends this workaround: "refactor the operation which requires a large stack to run in a separate thread and then block on thread.value."
You can also consider compiling a custom version of Ruby with your own choices for FIBER_MACHINE_STACK_ALLOCATION_SIZE and FIBER_VM_STACK_SIZE in the
cont.c
source file. That file also shows how fiber stacks are allocated, freed, etc.