Why the large difference between stack memory limit systems?

399 views Asked by At

I wrote an implementation of an algorithm for a course with Ruby 2.1 running in Ubuntu. The algorithm was easiest to express utilising recursion. Initially Ruby was raising the "stack level too deep SystemStack" exception due to the large memory requirements of the problem and implementation. To allow the algorithm to complete I used the following commands to increase the allowable stack size:

export RUBY_THREAD_VM_STACK_SIZE=16000000

ulimit -s 128000

Note that both commands above have to be run. The units of RUBY_THREAD_VM_STACK_SIZE is bytes and the units of ulimit is kBytes. So the RUBY_THREAD_VM_STACK_SIZE limit is ~16MBytes and the ulimit limit is ~128MBytes. If I reduce either limit by a half it's value shown here the algorithm won't finish without the exception.

Can someone please explain why these limits differ by a factor of ~8?

I've checked what I'm able to and it doesn't seem to be because one of the units is kbits instead of kBytes. Thanks!

1

There are 1 answers

0
rr- On BEST ANSWER

I believe the ulimit needs to be bigger due to Ruby's boilerplate around function calls.

In /vm_eval.c we see this:

  • rb_call0 - this is used to execute Ruby's functions. It accepts 6 arguments.
  • this in turn calls vm_call0, which accepts 7 arguments.
  • this in turn calls vm_call0_body which accepts 3 arguments.
  • this in turn calls vm_exec (located in vm.c) which accepts 1 argument.
  • at this point I'm a bit lost, but it calls vm_exec_core and a lot of other things.

Nonetheless from this hierarchy we see that Ruby pushed quite a bit on the stack just for this one function call: addresses to at least 5 functions and at least 17 arguments. That's 88 bytes.

That was the system stack. The Ruby's VM stack is something completely different and belongs to the Ruby's executable rather than being managed by the system. It holds only structures that Ruby needs to maintain in order to execute the functions, without the incidental boilerplate that gets pushed on the sytem stack resulting from Ruby's code structure.