resource.setrlimit
must also be used to increase the stack size and prevent segfault
The Linux kernel limits the stack of processes.
Python stores local variables on the stack of the interpreter, and so recursion takes up stack space of the interpreter.
If the Python interpreter tries to go over the stack limit, the Linux kernel makes it segmentation fault.
The stack limit size is controlled with the getrlimit
and setrlimit
system calls.
Python offers access to those system calls through the resource
module.
sys.setrecursionlimit
mentioned e.g. at https://mcmap.net/q/42074/-what-is-the-maximum-recursion-depth-and-how-to-increase-it only increases the limit that the Python interpreter self imposes on its own stack size, but it does not touch the limit imposed by the Linux kernel on the Python process.
Example program:
main.py
import resource
import sys
print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print
# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)
def f(i):
print i
sys.stdout.flush()
f(i + 1)
f(0)
Of course, if you keep increasing setrlimit
, your RAM will eventually run out, which will either slow your computer to a halt due to swap madness, or kill Python via the OOM Killer.
From bash, you can see and set the stack limit (in kb) with:
ulimit -s
ulimit -s 10000
The default value for me is 8Mb.
See also:
Tested on Ubuntu 16.10, Python 2.7.12.
997
then? Is it because Python interpreter occupies the first 3 levels of the stack? – Casperline <n>, in <module>
in stack traces) and this code takes 2 stack frames forn=1
(because the base case isn < 1
, so forn=1
it still recurses). And I guess the recursion limit is not inclusive, as in it's "error when you hit 1000" not "error if you exceed 1000 (1001)".997 + 2
is less than 1000 so it works998 + 2
doesn't because it hits the limit. – Lactalbumin997
stack frames are occupied byrecursive_function
and the last2
are occupied by the intepreter itself (builtin allocation)? Did I got it right? – Casperrecursive_function(997)
works, it breaks at998
. When you callrecursive_function(998)
it uses 999 stack frames and 1 frame is added by the interpreter (because your code is always run as if it's part of top level module), which makes it hit the 1000 limit. – Lactalbuminn+1
frames to calculate the result forn
. – Lactalbuminrecursion limit = 1000
,recursive_function(995, 0)
works whilerecursive_function(996, 0)
doesn't... So I guess there must be additional stack frames being used (I am using Python 3.6). – Caspermain()
function or importing a file where you're defining the function? If you're running it with IPython, I wouldn't be surprised if that adds a few frames as well. – Lactalbuminpython
and then write and execute the code on the interpreter's>>>
prompt. – Casperpython
and notpython3
it's probably 2 – Lactalbuminpython
on the CLI:Python 3.6.5 (default, Mar 30 2018, 06:42:10) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
– Casper