How to increase stack size for a ruby app. Recursive app getting: Stack level too deep (SystemStackError)
Ruby uses the C stack so your options include using ulimit or compiling Ruby with some compiler/linker stack size flag. Tail recursion is yet to be implemented and Ruby's current support for recursion isn't so great. As cool and elegant recursion is, you might want to consider coping with the language's limitations and writing your code in a different way.
Is it possible to create SystemStackError: stack level too deep errors without recursion?
In this example, does it detect the certainty of running out of stack or does it actually run out of stack?
It actually runs out of stack. It is, in fact, impossible to "detect the certainty of running out of stack" in the general case because of the halting problem, one of the core problems in computer science.
Is it possible to produce this error without using recursion?
Sure. Just define a lot of methods, each of which calls the next:
20000.times do |n|
define_method :"foo_#{n}" do
puts "Called #{__method__}"
send :"foo_#{n+1}"
end
end
foo_0
# -> Called foo_0
# -> Called foo_1
# -> Called foo_2
# -> Called foo_3
# ...
# -> Called foo_4931
# -> SystemStackError: stack level too deep
Ruby stack level too deep exception NOT from recursive infinite loop
Are there other cases that raise stack level too deep exception, besides the classical program-execution-tree-is-too-deep scenario?
Yes. Since the stack is not measured in depth, but in bytes, anything stored on the stack will fill it up sooner:
def recurse(depth=0)
recurse depth+1
rescue SystemStackError
depth
end
=> nil
recurse
=> 8717
def recurse(depth=0)
a,b,c = 1,2,3
recurse depth+1
rescue SystemStackError
depth
end
=> nil
recurse
=> 7264
def recurse(depth=0)
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z = *(0..25)
recurse depth+1
rescue SystemStackError
depth
end
=> nil
recurse
=> 3187
In this example, a function with only one variable can go several thousand calls deep before failing, and adding three more variables does very little; but adding 26 more variables balloons the stack size to a point where only around 3000 levels are available.
This will, of course depend somewhat on the ruby implementation, and the system it's running on. But I believe it will always hold as a general rule.
However, I still think recursion is likely your problem, since the number of variables required to have this happen at small call chain lengths is immense.
Is it possible to create SystemStackError: stack level too deep errors without recursion?
In this example, does it detect the certainty of running out of stack or does it actually run out of stack?
It actually runs out of stack. It is, in fact, impossible to "detect the certainty of running out of stack" in the general case because of the halting problem, one of the core problems in computer science.
Is it possible to produce this error without using recursion?
Sure. Just define a lot of methods, each of which calls the next:
20000.times do |n|
define_method :"foo_#{n}" do
puts "Called #{__method__}"
send :"foo_#{n+1}"
end
end
foo_0
# -> Called foo_0
# -> Called foo_1
# -> Called foo_2
# -> Called foo_3
# ...
# -> Called foo_4931
# -> SystemStackError: stack level too deep
Is there a workaround for stack level too deep errors in recursive routines?
If you're using YARV (the C based implementation of Ruby 1.9), you can tell the Ruby VM to turn tail call optimization on:
RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => true,
:trace_instruction => false
}
def countUpTo(current, final)
puts current
return nil if current == final
countUpTo(current+1, final)
end
countUpTo(1, 10_000)
Ruby profiler stack level too deep error
One workaround would be to turn tail call optimization on.
The following is an example of something that works with TCO on, but doesn't work when TCO is off.
RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => true,
:trace_instruction => false
}
def countUpTo(current, final)
puts current
return nil if current == final
countUpTo(current+1, final)
end
countUpTo(1, 10_000)
Related Topics
How to Wrap Link_To Around Some HTML Ruby Code
Counter_Cache With Has_Many :Through
How to Read Lines of a File in Ruby
Execute Bash Commands from a Rakefile
Rvm Warning! Path Is Not Properly Set Up
The Class/Object Paradox Confusion
Turning Long Fixed Number to Array Ruby
Best Way to Add Comments in Erb
Ruby Method Array#≪≪ Not Updating the Array in Hash
How to Install Therubyracer Gem on 10.10 Yosemite
How to Run Rake Tasks Within a Ruby Script
How to Assign Hash['A']['B']= 'C' If Hash['A'] Doesn't Exist
Ruby: Class Instance Variables VS Instance Variables