在Swift中递归调用期间的BAD_ACCESS

时间:2015-06-16 19:17:03

标签: swift recursion

在玩Swift的同时,我遇到了崩溃的情况,我仍然没有弄清楚原因。

让我们来定义:

class TestClass {

    var iteration: Int = 0

    func tick() -> Void{
        if iteration > 100000 {
            print("Done!")
            return
        }
        iteration++
        tick()
    }
}

tick()函数调用自身,每次递增iteration。任何类型的呼叫

let test = TestClass()
test.tick()

在相当少的递归(我的iMac上大约50000)之后使程序崩溃,并出现EXC_BAD_ACCESS错误:The EXC_BAD_ACCESS

如果我定义类似struct而不是class,则不会发生崩溃(至少不在这些限制范围内)。请注意,当它崩溃时,程序只使用几MB的RAM。

我无法解释为什么会崩溃。有人有解释吗? callbackStorage值似乎很可疑,但我还没有找到任何指针。

2 个答案:

答案 0 :(得分:6)

在你的程序中,每个线程都有一个名为 stack 的东西。堆栈是一个LIFO(后进先出) - 一个有两个主要操作的数据容器: push ,它将一个元素添加到堆栈的顶部, pop ,它从堆栈顶部删除一个项目。

当你的程序调用一个函数时,它会推送调用该函数的代码的位置,称为返回地址,(有时也是函数的一些参数),然后跳转到该函数的码。 (函数的局部变量也存储在堆栈中。)当函数返回时,它会弹出堆栈的返回地址并跳转到它。

但是,堆栈的大小有限。在您的示例中,您的函数调用自身很多次,以至于堆栈中没有足够的空间用于所有返回地址,参数和局部变量。这称为stack overflow(这是该网站的名称)。程序尝试写入堆栈的末尾,导致segfault

使用struct时程序不会崩溃的原因很可能是as dans3itz said,因为类的开销比结构更多。

答案 1 :(得分:3)

您遇到的运行时错误是堆栈溢出。在修改定义以使用结构时您没有遇到过这一事实并不意味着它不会发生。稍微增加迭代深度,您还可以使用struct实现实现相同的运行时错误。由于传递了隐式参数,它将更快地实现类实现。