stackoverflow出现的原因

    技术2022-07-10  113

    栈溢出(stack overflow)

    大家知道程序里面的函数是相互调用的,但是它的实现原理知道么? 这是一段C的代码,在main函数里面调用了add函数,下面是编译之后的汇编语言和机器码。 大家可以看到第34行代码是call指令,call指令后面跟着的,是跳转后的程序地址。

    我们来看add函数。可以看到,add函数编译之后,代码先执行了一条push指令和一条mov指令;在函数执行结束的时候,又执行了一条pop和一条ret指令。这四条指令的执行,其实就是在进行我们接下来要讲 压栈(Push)和 出栈(Pop)操作。

    这里是在原来顺序执行的指令过程里,执行了一个内存地址的跳转指令,让指令从原来顺序执行的过程里跳开,从新的跳转后的位置开始执行。

    那我们又如何让跳转后执行完目标函数,返回到调用处那?

    1.首相我们可以将调用的代码填充到调用处,如果A函数调用B,B函数代码直接填充到A函数中,这样是没问题的;但是如果A调用B,B也调用A,这下你该如何?显然,这样行不通。 2.我们可以把调用处的地址记录在寄存器里面,但是调用多次,显然,寄存器也不够用了。 上面两个方法肯定走不通,于是科学家想出了在内存里面开辟一段空间,用栈这个 后进先出(LIFO,Last In First Out)的数据结构。

    栈就像一个乒乓球桶,每次程序调用函数之前,我们都把调用返回后的地址写在一个乒乓球上,然后塞进这个球桶。这个操作其实就是我们常说的 压栈。如果函数执行完了,我们就从球桶里取出最上面的那个乒乓球,很显然,这就是出栈。拿到出栈的乒乓球,找到上面的地址,把程序跳转过去,就返回到了函数调用后的下一条指令了。

    其实你对JAVA的JVM有一定了解的人,它的方法调用也是和上面的图解一样的。

    因为栈的大小固定的,你在不断的压栈,栈的空间肯定会使用完毕,之后再压入,肯定会出现栈溢出(stack overflow),在平常开发中,递归调用中容易出现。

    Processed: 0.033, SQL: 9