什么是vb.net中的StackOverFlow异常?

3
我甚至不知道是什么原因导致了这个问题。它是什么?我创建了一个类的新实例(该类在另一个文件中),但第一次调用方法时它抛出了StackOverFlow异常。
我唯一认为可能会逻辑上引发stackoverflow异常的事情就是如果有人给Jon Skeet点了踩。
但说真的,它是什么?我通过在与第一个类相同的文件中创建另一个类并使用它来调用方法来解决了这个问题。

也许提供错误信息和相关源代码能够帮助我们解决这个谜题。 - Kevin LaBranche
2
对Jon进行负面评价会导致蓝屏死机。 :) - Kevin LaBranche
不会回去重新破坏我的代码,因为它不在源代码控制下,我也不想破坏已经工作的东西。我有点担心Jon现在会看到这个问题哈哈。 - Cyclone
你应该……如果Jon看到这个并感到不满,你将会遇到另一个无法解释的堆栈溢出。 - Kevin LaBranche
当然,那个stackoverflow会导致BSOD(蓝屏死机),从而物理上断开连接到我的显示器的电线。更糟糕的是,这是一台笔记本电脑 >.< - Cyclone
9个回答

6

一般情况下,堆栈溢出异常是由递归算法引起的,其中递归深度超过了(通常)固定的堆栈限制。这通常是算法中的bug导致的,但也可能是因为应用算法的数据结构太“深”。

以下是一个简单的有bug的递归示例(不特定于任何编程语言)。

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

在典型的编程语言中,对于非空列表调用length方法会导致堆栈溢出。即使你修正了这个错误,对于一个很长的列表调用该方法也可能会导致堆栈溢出。

(例外情况是当你使用支持尾递归优化的语言...或更严格地说,编译器时)


算法设置自己最多调用100次,为什么会抛出异常?请注意,只有在另一个文件中时才会抛出异常,在同一文件中不会发生任何事情。 - Cyclone
我很快会在我的网站上发布源代码,我正在研究 MDI 并且当您尝试添加多个子窗口时调用的代码是被称为。主类中的 For 循环用于父窗口被设置为无论如何都要少于 100 次。将 addchild 子程序调用移动到同一文件中会有什么影响? - Cyclone

4

堆栈溢出异常是指超出分配的堆栈大小,通常发生在递归调用方法并永远不离开时,也可能由于各种晦涩的方法链引起。问题可能是你的对象中有类似以下代码:

void MyMethod()
{
    MyMethod();
}

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

P.S. SO是为特定的异常命名的(这是基本原理,并不限于.NET),它只是一个开发人员网站的巧妙名称。


哈哈,我知道它是以那个命名的,这也有点双关语,因为标志是一堆溢出的文件,即收件箱中有太多工作需要帮助。 - Cyclone

2

StackOverFlows的异常就是它字面意思所表达的,堆栈溢出。通常情况下,这是因为你的方法存在循环依赖关系。例如,方法A调用B,而B又调用A。或者这可能是一个没有基本情况的递归方法。


2

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


2
栈是计算机存储当前被调用的函数、变量和参数列表的地方。例如,如果函数Main调用函数A,然后函数A又调用函数B,并使用变量c、d和e,则栈将包含所有这些信息。但是,栈的大小是有限的。因此,如果函数B再调用函数C,函数C再调用函数D...等等,最终可能会出现数百个嵌套函数,栈就会“溢出”——没有足够的空间来存储另一个函数调用。
正如其他人所指出的,这通常发生在递归函数中(其中函数B调用函数B,然后函数B再调用函数B...)——最终,栈会溢出。您需要找到递归函数被调用的位置以及为什么它没有在应该退出递归循环时退出。
当然,问题可能不是由于错误的递归算法,而只是因为函数调用的数量超过了栈的大小。因此,如果您的算法可能会调用递归函数几百次,那就可能是这个原因。

1

这通常是由于对一个函数进行递归调用,而该递归调用永远不会终止所导致的。您可能会以几种方式遇到这种情况。一种方式可能是没有基本情况的递归算法,另一种常见的方式是在它们的构造函数中创建相互创建一个A和B对象等。

我建议您通过调试器逐步查找并找出问题 :)


0

我遇到了这个问题,我注意到我打错了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

0
最近,我将一个旧的 VB6 应用程序移植到 VB.NET,该应用程序使用一个庞大的递归函数来对等量的数据进行排序。算法本身没有问题,但执行过程中一直导致堆栈溢出错误。经过多次尝试后,我发现 VB 在代码后面做了太多的“魔法”:轻松的类型转换是有代价的。因此,递归函数过于依赖晚期绑定,而不是使用类型变量,这导致了大量的强制转换、解析等开销(一行代码可以调用从 2 到 10 个函数……),显然,这导致了堆栈溢出。

简而言之:在递归函数中使用 DirectCast() 和静态绑定(具有类型的变量)以防止 VB 在运行时向堆栈中洪水般地注入数据。


-1

我遇到了一个Stackoverflow错误。 我正在使用一个将1添加到计数器然后重新调用相同例程的例程。 大约每2500到3000个循环,我都会收到stackoverflow错误。 我已经添加了一个DO...Loop来调用该例程,我使用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之后,我的程序运行了40000次而没有出现“堆栈溢出”的情况。


1
请在编辑器中突出显示您的代码,并将其标记为实际代码! - Thomas Wagenaar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接