无限递归循环编译器是如何处理的

来源:互联网 发布:电视上安装网络机顶盒 编辑:程序博客网 时间:2024/05/16 11:19

不管是C语言还是python ,都支持递归调用,就是函数call 自己,那什么时候,才是个头呢?就是说,什么时候,才跳出循环呢?

consider the following code:

def foo():    foo()try:    foo()except RuntimeError:    print("RuntimeError")


按道理,这个函数会一直走下去,直到将内存吃完,但这肯定是操作系统不允许的。所以,我们还是会让他走一段时间,然后打印出 RuntimeError。




那具体是如何做到的呢?

这里就要说到一个经常被提到,但又不知道到底是啥的概念, stack, 俗称 栈

坊间流传这样一个说法: inus Torvalds说“Talk is cheapShow me the code

 接下来,我就用代码挨个说明,背后的实现方式:


void mp_stack_ctrl_init(void) {    volatile int stack_dummy;    MP_STATE_THREAD(stack_top) = (char*)&stack_dummy;    /*    * 这个函数,应该说还是设计的很巧妙, stack_dummy 类型为volative, 就是说它的值是随时可以变的    * 第二个,它又是local variable, local variable 刚好就是分配在stack上面的,表达式(char*)&stack_dummy    * 各符号的作用依次为 取出地址,拿到值,然后给stack_top (就是保存起来)。注意,这个函数是在程序最开头运行的。    * 就是在程序的最开头,设定一个临界值,栈不能超过这个范围。    */}void mp_stack_set_top(void *top) {/*     * 设置top     */    MP_STATE_THREAD(stack_top) = top;}mp_uint_t mp_stack_usage(void) {    /*     * 检查栈用超了没有,即用栈顶地址,减去当前局部变量所拥有有地址。即程序的栈当前已经用了多少内存了     */    // Assumes descending stack    volatile int stack_dummy;    return MP_STATE_THREAD(stack_top) - (char*)&stack_dummy;}#if MICROPY_STACK_CHECKvoid mp_stack_set_limit(mp_uint_t limit) {    /*     *  给栈设定一个极限,函数用超了,就抛出异常。比如设为1M。     */    MP_STATE_THREAD(stack_limit) = limit;}void mp_exc_recursion_depth(void) {    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OverflowError,        MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));}void mp_stack_check(void) {    /*    * 如果用掉的内存,大于所指定的极限值,即调用抛出异常胡handler.    */    if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) {        mp_exc_recursion_depth();    }}#endif // MICROPY_STACK_CHECK



写到这里,大家可能会想到一个问题,关于对stack 使用的情况,什么时候检查呢?


答案就是每次调用obj 的成员函数之前,做一次检查。如果指定的栈用完了,后面的程序不跑了。


原创粉丝点击