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://stackoverflow.com/a/3323013/895245 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.
line <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. – Borisrecursive_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. – Boris