In Ruby, what is stored on the stack?

2019-02-05 20:28发布

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

1条回答
Juvenile、少年°
2楼-- · 2019-02-05 21:03

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:

"The entire space that an object takes up in memory is not stored inside the Slot. Rather each Slot is a small fixed size space which can be thought of as the Ruby interpreter's handle a location in memory. This location exists outside of the Ruby Heap itself and contains the real 'meat' of the object. To be clear, if you have a 50MB string - the 50MB of data is stored outside of Ruby's Heap. If you really want to know the story of the 50MB, the space for it is actually allocated by something like the malloc command in C (as good ol' Ruby is written in C) and then stored on the System Heap. The Slot in the Ruby Heap simply contains a reference to that memory location on the System Heap which contains the 50MB of data."

"Ruby has it's own heap management which actually consists of several 'Ruby Heaps' to manage objects created during the execution of a Ruby program; this is separate from the System Heap for your Operating System. Each individual Ruby Heap contains Slots, with each Slot able to one reference one object.

Another good source is "How Ruby Manages Memory and Garbage Collection", which links to slides at "Garbage Collection Slides from LA Ruby Conference".

"As a garbage collected language, Ruby takes the easy route by putting everything on the heap".

Fibers

Fibers are special in Ruby because each fiber gets its own small stack.

"As opposed to other stackless light weight concurrency models, each fiber comes with a small 4KB stack. This enables the fiber to be paused from deeply nested function calls within the fiber block."

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.

查看更多
登录 后发表回答