【问题标题】:What is a StackOverFlow exception in vb.net?vb.net 中的 StackOverFlow 异常是什么?
【发布时间】:2017-07-02 14:56:30
【问题描述】:

我什至不知道是什么导致了我的申请。它是什么?我创建了一个类的新实例(该类在另一个文件中),但在第一次调用一个方法时,它会引发 StackOverFlow 异常。

我认为逻辑上唯一会引发 stackoverflow 异常的事情是,如果有人对 Jon Skeet 投了反对票。

但现在说真的,它是什么?我通过在与第一个类相同的文件中创建另一个类并使用它为我调用方法来解决它。

【问题讨论】:

  • 也许您的错误转储和一些来源可以帮助我们为您解答这个谜题。
  • 拒绝 Jon 实际上会导致 BSOD。 :)
  • 不会回去重新破坏我的代码,因为它不受源代码控制,我不想破坏有效的东西。我有点担心乔恩现在会看到这个问题哈哈。
  • 你应该......
  • 当然,stackoverflow 会导致 BSOD(黑屏死机),从而物理断开连接到我的显示器的电线。更糟糕的是,这是一台笔记本电脑>.

标签: exception stack-overflow


【解决方案1】:

作为一般规则,堆栈溢出异常是由递归算法引起的,其中递归深度已超过(通常)固定堆栈限制。这通常是算法中的错误导致的,但也可能是由于您应用算法的数据结构过于“深”。

这是一个错误递归的简单示例(在没有特定的 PL 中)。

function int length(list l) {
    if (empty(l)) {
        return 0;
    } else {
        return 1 + length(l);  // should be 'return 1 + length(tail(l));
    }
}

在典型的编程语言中,任何非空列表的调用长度都会导致堆栈溢出。但是即使你改正了这个bug,对长列表调用方法也很可能导致堆栈溢出。

(例外情况是当您使用一种语言......或更严格地说是编译器......支持尾递归优化。)

【讨论】:

  • 算法设置自己调用不超过100次,为什么会抛出这个?请注意,它仅在另一个文件中被抛出,从同一个文件中它没有做任何事情。
  • 我的网站上很快就会有源代码,我在玩 MDI,当您尝试添加多个子窗口时调用了有问题的代码,父窗口的主类中的 For 循环不惜一切代价设置为少于 100 次。将 addchild sub 的调用移动到同一个文件应该做什么?
【解决方案2】:

堆栈溢出异常是当您超出分配的堆栈大小时,这通常发生在递归调用方法并且永不离开,也可能是由各种模糊的方法链接引起的。问题是您可能在对象中有以下内容。

void MyMethod()
{
    MyMethod();
}

调用将耗尽并且永远不会释放使用的堆栈空间,因为调用永远不会结束执行并且入口点必须保留。

附: SO 以所讨论的特定异常命名(这是基本的,不仅限于 .NET),它只是开发人员站点的一个聪明的名称。

【讨论】:

  • 大声笑,我知道它就是以此命名的,它也是一种双关语,因为徽标是一堆溢出的文件,即收件箱中的工作太多,您需要帮助。
【解决方案3】:

StackOverFlows 异常就像它们听起来的样子,堆栈溢出。通常这是因为您的方法中有循环依赖。例如方法 A 调用 B,B 调用 A。或者它可能是没有基本情况的递归方法。

【讨论】:

    【解决方案4】:

    没有看到代码就不可能知道为什么会发生这种情况,但是当线程溢出其调用堆栈时会抛出StackOverflowException。这最常发生在方法以递归方式调用自身而没有任何条件中断从而创建无限递归时。由于每次递归都会创建一个新的堆栈帧,因此理论上无限递归会创建无限数量的堆栈帧,我相信您现在可以理解为什么“堆栈溢出”这个术语是恰当的了。

    【讨论】:

      【解决方案5】:

      堆栈是计算机存储当前正在调用的函数列表以及使用的变量和参数的地方。因此,如果函数 Main 调用函数 A,然后函数 A 调用函数 B,并且它们使用变量 c、d 和 e,则堆栈将包含所有这些信息。但是,堆栈只有这么大。因此,如果函数 B 然后调用函数 C,后者调用函数 D... 等等,最终会产生数百个嵌套函数,最终,堆栈将“溢出” - 没有足够的空间来存储另一个函数调用。

      正如其他人所指出的,这通常发生在递归函数中(函数 B 调用函数 B,然后函数 B 调用函数 B...) - 最终,堆栈将溢出。您将需要找到调用该递归函数的位置,以及为什么它没有在应退出的递归循环中跳出。

      当然,问题可能不在于它是一个有缺陷的递归算法——它可能只是函数调用的数量超过了堆栈的大小。所以如果你的算法有可能调用一个递归函数几百次,它可能就是这样。

      【讨论】:

        【解决方案6】:

        这通常是由对函数的递归调用引起的,该函数的递归调用永远不会终止。您可以通过多种方式获得此信息。一种方法可能是没有基本情况的递归算法,另一种常见的方法是创建对象 A 和 B,它们在它们的构造函数中相互创建,等等。

        我建议您逐步调试并找出答案:)

        【讨论】:

          【解决方案7】:

          我最近将一个旧的 VB6 应用程序移植到 VB.NET,它使用了一个可怕的递归函数来对同样大量的数据进行排序。该算法很好,但执行始终导致堆栈溢出错误。经过一番折腾,我意识到 VB 在代码背后做了很多魔法:简单的类型转换是有代价的。所以递归函数过于依赖后期绑定而不是使用类型变量,这导致了大量的转换、解析等开销(一行代码可以调用 2 到 10 个函数......)其中,显然,使堆栈溢出。

          TL;DR:使用 DirectCast() 和静态绑定(类型化变量)来防止 VB 在运行时在递归函数中淹没堆栈。

          【讨论】:

            【解决方案8】:

            我遇到了这个问题,我注意到我输入了错误的 lstEncounter。正如我在我的 C++ 课程中学到的,问题在于递归算法基本上使用相同的参数调用自身。我收到错误的示例:

            Property Encounter(ByVal N As Integer)
                Get
                    If N < lstEncounters.Count Then
                        Return Encounter(N)
                    Else
                        Return Nothing
                    End If
                End Get
                Set(value)
                    lstEncounters(N) = value
                End Set
            End Property
            

            【讨论】:

              【解决方案9】:

              我遇到了 Stackoverflow 错误。 我正在使用一个将 1 添加到计数器的例程,然后重新调用相同的例程。 大约每 2500 到 3000 个循环,我就会收到 stackoverflow 错误。 我添加了一个调用例程的 DO...循环,我使用 VB Express:

              之前:

              Public Sub mainloop()
              
              Dim cntr as integer
              
              If cntr >= 5000  ( I just picked a number at random)
              
                  me.close  ( I close the program)
              
              ...               (This is where I would manipulate the cntr for diff 
              results)
              
              cntr = cntr + 1  ( increment the cntr)
              
              mainloop()        (re call my loop) 
              
              End IF
              
              End Sub
              

              (正如我之前所说,大约 2500-3000 之后我会收到 Stackoverflow 错误)

              AFTER:(先执行)

              Dim LoopCntr as integer
              
              Do While LoopCntr <= 40000  (this my number.. Use your own number)
              
              If LoopCntr > 40000 Then
              
                      Exit Do
              End If
              
              mainloop()       (The mainloop() has not been changed just the method of calling it)
              LoopCntr = LoopCntr + 1
              
              Loop
              
              me.close        (When LoopCntr reaches max it closes the program)
              

              (添加 Do..Loop 后,我的程序在没有“Stackoverflow”的情况下运行了 40000 次)

              【讨论】:

              • 请在编辑器中突出显示您的代码并将其标记为实际代码!
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-01
              • 1970-01-01
              • 1970-01-01
              • 2012-06-21
              相关资源
              最近更新 更多