如何处理 Java 中的 StackOverflowError?

发布于 07-24 03:44 字数 1436 浏览 3 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

无敌元气妹2024-07-31 03:44:13

查看 Raymond Chen 的帖子 调试堆栈溢出时,您需要关注重复的递归部分。 摘录:

如果您搜索缺陷跟踪数据库,试图了解这是否是一个已知问题,则搜索堆栈上的顶级函数不太可能找到任何有趣的东西。 这是因为堆栈溢出往往发生在递归中的随机点; 每个堆栈溢出看起来都与其他堆栈溢出表面不同,即使它们是相同的堆栈溢出。

假设您正在唱Frère Jacques这首歌,只不过您唱的每一节都比前一节高几个音调。 最终,你将达到你的歌唱范围的顶峰,而达到顶峰的具体位置取决于你的声乐极限与旋律的匹配程度。 旋律中,前三个音符各创一个新的“纪录高点”(即该音符比迄今为止所唱的任何其他音符都高),新的纪录高点出现在第三小节的三个音符中,最后一个记录第五小节第二个音符的高音。

如果旋律代表程序的堆栈使用情况,则堆栈溢出可能会发生在程序执行过程中这五个位置中的任何一个位置。 换句话说,相同的潜在失控递归(在音乐上表现为旋律的更高演绎)可以以五种不同的方式表现出来。 这个类比中的“递归”相当快,在循环重复之前只有八个小节。 在现实生活中,循环可能会很长,导致数十个潜在的堆栈溢出点。

如果您面临堆栈溢出,那么您需要忽略堆栈顶部,因为它只关注超出您音域的特定音符。 您确实想找到整个旋律,因为这是具有相同根本原因的所有堆栈溢出的共同点。

Take a look at Raymond Chen's post When debugging a stack overflow, you want to focus on the repeating recursive part. An extract:

If you go hunting through your defect tracking database trying to see whether this is a known issue or not, a search for the top functions on the stack is unlikely to find anything interesting. That's because stack overflows tend to happen at a random point in the recursion; each stack overflow looks superficially different from every other one even if they are the same stack overflow.

Suppose you're singing the song Frère Jacques, except that you sing each verse a few tones higher than the previous one. Eventually, you will reach the top of your singing range, and precisely where that happens depends on where your vocal limit lines up against the melody. In the melody, the first three notes are each a new "record high" (i.e., the notes are higher than any other note sung so far), and new record highs appear in the three notes of the third measure, and a final record high in the second note of the fifth measure.

If the melody represented a program's stack usage, a stack overflow could possibly occur at any of those five locations in the program's execution. In other words, the same underlying runaway recursion (musically represented by an ever-higher rendition of the melody) can manifest itself in five different ways. The "recursion" in this analogy was rather quick, just eight bars before the loop repeated. In real life, the loop can be quite long, leading to dozens of potential points where the stack overflow can manifest itself.

If you are faced with a stack overflow, then, you want to ignore the top of the stack, since that's just focusing on the specific note that exceeded your vocal range. You really want to find the entire melody, since that's what's common to all the stack overflows with the same root cause.

萌化2024-07-31 03:44:13

您可能想查看您的 JVM 是否支持“-Xss”选项。 如果是这样,您可能想尝试将其设置为 512k(在 32 位 Windows 和 Unix 下默认为 256k),看看这是否有任何作用(除了让您在出现 StackOverflowException 之前等待更长时间)。 请注意,这是每个线程的设置,因此如果您有很多线程正在运行,您可能还需要提高堆设置。

You might want to see if the "-Xss" option is supported by your JVM. If so, you might want to try setting it to a value of 512k (default is 256k under 32-bit Windows and Unix) and see if that does anything (other than make you sit longer until your StackOverflowException). Note that this is a per-thread setting, so if you've got a lot of threads running you also might want to bump up your heap settings.

久光2024-07-31 03:44:13

正确答案是已经给出的答案。 您可能 a) 代码中存在导致无限递归的错误,这通常很容易诊断和修复,或者 b) 代码可能导致非常深的递归,例如递归遍历不平衡的二叉树。 在后一种情况下,您需要更改代码以不在堆栈上分配信息(即不递归),而是在堆中分配信息。

例如,对于不平衡的树遍历,您可以将需要重新访问的节点存储在 Stack 数据结构中。 对于有序遍历,您将沿着左分支循环,在访问每个节点时推动每个节点,直到遇到要处理的叶子,然后从堆栈顶部弹出一个节点,处理它,然后使用以下命令重新启动循环右子节点(只需将循环变量设置为右节点。)这将通过将堆栈上的所有内容移动到堆栈数据结构中的堆来使用恒定数量的堆栈。 堆通常比堆栈丰富得多。

这通常是一个非常糟糕的主意,但在内存使用受到极大限制的情况下是必要的,您可以使用指针反转。 在这种技术中,您将堆栈编码到您正在遍历的结构中,并且通过重用您正在遍历的链接,您可以在不需要或显着减少额外内存的情况下完成此操作。 使用上面的例子,我们不需要在循环时推送节点,而是只需要记住我们的直接父节点,并且在每次迭代时,我们将遍历的链接设置为当前父节点,然后将当前父节点设置为我们要离开的节点。 当我们到达一片叶子时,我们对其进行处理,然后去找我们的父母,然后我们遇到了一个难题。 我们不知道是否要纠正左分支,处理该节点,然后继续处理右分支,或者纠正右分支并转到父分支。 因此,我们需要在迭代时分配额外的信息。 通常,对于该技术的低级实现,该位将存储在指针本身中,从而导致总体上不需要额外的内存和常量内存。 这在 Java 中不是一个选项,但可以将这一点存储在用于其他用途的字段中。 在最坏的情况下,所需内存量仍会减少至少 32 或 64 倍。 当然,这种算法非常容易出错,结果完全混乱,并且会对并发性造成严重破坏。 因此,除非分配内存无法维持,否则几乎不值得进行维护噩梦。 典型的例子是垃圾收集器,其中类似的算法很常见。

不过,我真正想讨论的是当您可能想要处理 StackOverflowError 时。 即在 JVM 上提供尾调用消除。 一种方法是使用蹦床样式,而不是执行尾部调用,您返回一个空过程对象,或者如果您只是返回一个值,则返回该值。 [注意:这需要某种方法来表示函数返回 A 或 B。在 Java 中,最简单的方法可能是正常返回一种类型并抛出另一种类型作为异常。]需要执行一个 while 循环来调用无效过程(其本身将返回无效过程或值),直到获得值。 无限循环将变成 while 循环,不断强制返回过程对象的过程对象。 蹦床风格的好处是,它只使用比正确消除所有尾部调用的实现多一个常数因子的堆栈,它使用普通的 Java 堆栈来进行非尾部调用,转换简单,并且只增加通过(繁琐的)常数因子编写代码。 缺点是您在每个方法调用上分配一个对象(这将立即变成垃圾),并且消耗这些对象涉及每个尾调用的几次间接调用。

理想的做法是从一开始就不分配那些无效过程或其他任何东西,这正是尾调用消除所要实现的目标。 不过,使用 Java 提供的功能,我们可以做的是正常运行代码,并且仅在堆栈耗尽时才执行这些无效过程。 现在我们仍然分配那些无用的帧,但我们在堆栈而不是堆上进行分配,并批量释放它们,而且,我们的调用是正常的直接 Java 调用。 描述这种转换的最简单方法是首先将所有多调用语句方法重写为具有两个调用语句的方法,即 fgh() { f(); G(); H(); } 变成 fgh() { f(); gh(); } 和 gh(){ g(); H(); }。 为简单起见,我假设所有方法都以尾部调用结束,可以通过将方法的其余部分打包到单独的方法中来安排尾部调用,但实际上,您希望直接处理这些方法。 在这些转换之后,我们有三种情况,要么一个方法有零次调用,在这种情况下没有什么可做的,要么它有一个(尾部)调用,在这种情况下,我们将它包装在一个 try-catch 块中,就像我们将在两次调用情况下的尾部调用。 最后,它可能有两个调用,一个非尾部调用和一个尾部调用,在这种情况下,我们应用示例中说明的以下转换(使用 C# 的 lambda 表示法,可以轻松地用具有一定增长的匿名内部类替换)

// top-level handler
Action tlh(Action act) {
    return () => {
        while(true) {
            try { act(); break; } catch(Bounce e) { tlh(() => e.run())(); }
        }
    }
}

gh() {
    try { g(); } catch(Bounce e) { 
        throw new Bounce(tlh(() => { 
            e.run(); 
            try { h(); } catch(StackOverflowError e) {
                throw new Bounce(tlh(() => h());
            }
        }); 
    }
    try { h(); } catch(StackOverflowError e) { 
        throw new Bounce(tlh(() => h())); 
    }
}

:这里的主要好处是,如果没有抛出异常,这与我们开始时安装的一些额外异常处理程序的代码相同。 由于尾部调用(h() 调用)不处理 Bounce 异常,因此该异常将飞过它们,从堆栈中展开那些(不必要的)帧。 非尾部调用捕获 Bounce 异常并重新抛出它们并添加剩余的代码。 这会将堆栈一直展开到顶层,消除尾部调用帧,但记住空过程中的非尾部调用帧。 当我们最终执行顶层的 Bounce 异常中的过程时,我们将重新创建所有非尾部调用帧。 此时,如果我们立即再次耗尽堆栈,那么,由于我们不重新安装 StackOverflowError 处理程序,它将不会按预期捕获,因为我们确实已经耗尽堆栈。 如果我们更进一步,将根据需要安装一个新的 StackOverflowError。 此外,如果我们确实取得了进展,但随后再次耗尽堆栈,则重新展开我们已经展开的帧没有任何好处,因此我们安装新的顶级处理程序,以便堆栈只会展开到它们。

这种方法的最大问题是,您可能想要调用普通的 Java 方法,并且调用时堆栈空间可能非常小,因此它们可能有足够的空间来启动但无法完成,并且您无法在中间。 对此至少有两种解决方案。 第一个是将所有此类工作发送到一个单独的线程,该线程将拥有自己的堆栈。 这是非常有效和简单的,并且不会引入任何并发性(除非您想要它)。另一种选择是在调用任何普通 Java 方法之前通过简单地在调用任何普通 Java 方法之前立即抛出 StackOverflowError 来故意展开堆栈。 如果当你恢复时它仍然耗尽堆栈空间,那么你一开始就完蛋了。

也可以做类似的事情来及时延续。 不幸的是,这种转换实际上无法在 Java 中手动完成,并且对于 C# 或 Scala 等语言来说可能是边界。 因此,像这样的转换往往是由针对 JVM 的语言完成的,而不是由人完成的。

The correct answer is the one already given. You likely either a) have a bug in your code leading to an infinite recursion which is usually quite easy to diagnose and fix, or b) have code which can lead to very deep recursions for example recursively traversing an unbalanced binary tree. In the latter situation, you need to alter your code to not allocate the information on the stack (i.e. to not recurse) but to instead allocate it in the heap.

For example, for an unbalanced tree traversal, you could store the nodes that will need to be revisited in a Stack data structure. For an in order traversal you would loop down the left branches pushing each node as you visited it until you hit a leaf, which you would process, then pop a node off the top of the stack, process it, then restart your loop with the right child (by just setting your loop variable to the right node.) This will use a constant amount of stack by moving everything that was on the stack to the heap in the Stack data structure. Heap is typically much more plentiful than stack.

As something that is usually an extremely bad idea, but is necessary in cases where memory use is extremely constrained, you can use pointer reversal. In this technique, you encode the stack into the structure you are traversing, and by reusing the links you are traversing, you can do this with no or significantly less additional memory. Using the above example, instead of pushing nodes when we loop, we just need to remember our immediate parent, and at each iteration, we set the link we traversed to the current parent and then the current parent to the node we are leaving. When we get to a leaf, we process it, then go to our parent and then we have a conundrum. We don't know whether to correct the left branch, process this node, and continue with the right branch, or to correct the right branch and go to our parent. So we need to allocate an extra bit of information as we iterate. Typically, for low-level realizations of this technique, that bit will be stored in the pointer itself leading to no additional memory and constant memory overall. This is not an option in Java, but it may be possible to squirrel away this bit in fields used for other things. In the worst-case, this is still at least 32 or 64 times reduction in the amount of memory needed. Of course, this algorithm is extremely easy to get wrong with completely confusing results and would raise utter havoc with concurrency. So it's almost never worth the maintenance nightmare except where allocating memory is untenable. The typical example being a garbage collector where algorithms like this are common.

What I really wanted to talk about, though, is when you might want to handle the StackOverflowError. Namely to provide tail call elimination on the JVM. One approach is to use trampoline style where instead of performing a tail call you return a nullary procedure object, or if you are just returning a value you return that. [Note: this requires some means of saying a function returns either A or B. In Java, probably the lightest way to do this is to return one type normally and throw the other as an exception.] Then whenever you call a method, you need to do a while loop calling the nullary procedures (which will themselves return either a nullary procedure or a value) until you get a value. An endless loop will become a while loop that is constantly forcing procedure objects that return procedure objects. The benefits of trampoline style is that it only uses a constant factor more stack than you would use with an implementation that properly eliminated all tail calls, it uses the normal Java stack for non-tail calls, the translation simple, and it only grows the code by a (tedious) constant factor. The drawback is you allocate an object on every method call (which will immediately become garbage) and consuming these objects involves a couple of indirect calls per tail call.

The ideal thing to do would be to never allocate those nullary procedures or anything else in the first place, which is exactly what tail call elimination would accomplish. Working with what Java provides though, what we could do is run the code as normal and only make these nullary procedures when we run out of stack. Now we still allocate those useless frames, but we do so on the stack rather than the heap and deallocate them in bulk, also, our calls are normal direct Java calls. The easiest way to describe this transformation is to first rewrite all multi-call-statement methods into methods that have two call statements, i.e. fgh() { f(); g(); h(); } becomes fgh() { f(); gh(); } and gh(){ g(); h(); }. For simplicity, I'll assume all methods end in a tail call, which can be arranged by just packaging the remainder of a method into a separate method, though in practice, you'd want to handle these directly. After these transformations we have three cases, either a method has zero calls in which case there is nothing to do, or it has one (tail) call, in which case we wrap it in a try-catch block in the same we will for the tail call in the two call case. Finally, it may have two calls, a non-tail call and a tail call, in which case we apply the following transformation illustrated by example (using C#'s lambda notation which could easily be replaced with an anonymous inner class with some growth):

// top-level handler
Action tlh(Action act) {
    return () => {
        while(true) {
            try { act(); break; } catch(Bounce e) { tlh(() => e.run())(); }
        }
    }
}

gh() {
    try { g(); } catch(Bounce e) { 
        throw new Bounce(tlh(() => { 
            e.run(); 
            try { h(); } catch(StackOverflowError e) {
                throw new Bounce(tlh(() => h());
            }
        }); 
    }
    try { h(); } catch(StackOverflowError e) { 
        throw new Bounce(tlh(() => h())); 
    }
}

The main benefit here is if no exception is thrown, this is the same code as we started with just with some extra exception handlers installed. Since tail calls (the h() call) don't handle the Bounce exception, that exception will fly through them unwinding those (unnecessary) frames from the stack. The non-tail calls catch the Bounce exceptions and rethrow them with the remaining code added. This will unwind the stack all the way up to the top level, eliminating the tail call frames but remembering the non-tail call frames in the nullary procedure. When we finally execute the procedure in the Bounce exception at the top-level, we will recreate all the non-tail call frames. At this point, if we immediately run out of stack again, then, since we don't reinstall the StackOverflowError handlers, it will go uncaught as desired, since we really are out of stack. If we get a little further, a new StackOverflowError will be installed as appropriate. Furthermore, if we do make progress, but then do run out of stack again, there is no benefit re-unwinding the frames we already unwound, so we install new top-level handlers so that the stack will only be unwound up to them.

The biggest problem with this approach is that you'll probably want to call normal Java methods and you may have arbitrarily little stack space when you do, so they may have enough space to start but not finish and you can't resume them in the middle. There are at least two solutions to this. The first is to ship all such work to a separate thread which will have it's own stack. This is pretty effective and pretty easy and won't introduce any concurrency (unless you want it to.) Another option is simply to purposely unwind the stack before calling any normal Java method by simply throwing a StackOverflowError immediately before them. If it still runs out of stack space when you resume, then you were screwed to begin with.

A similar thing can be done to make continuations just-in-time too. Unfortunately, this transformation isn't really bearable to do by hand in Java, and is probably borderline for languages like C# or Scala. So, transformations like this tend to be done by languages that target the JVM and not by people.

原来是傀儡2024-07-31 03:44:13

我想你不能——或者它至少取决于你使用的jvm。 堆栈溢出意味着没有空间来存储局部变量和返回地址。 如果您的 jvm 执行某种形式的编译,那么 jvm 中也会出现 stackoverflow,这意味着您无法处理或捕获它。 jvm 必须终止。

可能有一种方法可以创建允许这种行为的 jvm,但速度会很慢。

我还没有测试过 jvm 的行为,但在 .net 中你无法处理 stackoverflow。 即使尝试捕获也无济于事。 由于 java 和 .net 依赖于相同的概念(带有 jit 的虚拟机),我怀疑 java 的行为会相同。 .NET 中存在 stackoverflow-Exception 表明,可能存在某些 vm 确实使程序能够捕获它,但正常情况则不会。

I guess you can't - or it at least depends on the jvm you use. Stack overflow means, that you have no room to store local variables and return adresses. If your jvm does some form of compiling, you have the stackoverflow in the jvm as well and that means, you can't handle it or catch it. The jvm has to terminate.

There could be a way to create a jvm that allows for such behavior, but it would be slow.

I have not tested the behavior with the jvm, but in .net you just can't handle the stackoverflow. Even try catch won't help. Since java and .net rely on the same concept (virtual machines with jit) I suspect java would behave the same. The presence of a stackoverflow-exception in .NET suggests, there might be some vm that does enable the program to catch it, the normal does not though.

为人所爱2024-07-31 03:44:13

获得 StackOverflowError 的大多数机会是在递归函数中使用[长/无限]递归。

您可以通过更改应用程序设计以使用可堆叠数据对象来避免函数递归。 有一些编码模式可以将递归代码转换为迭代代码块。 看看下面的答案:

因此,您可以通过使用自己的数据堆栈来避免 Java 对隐性函数调用进行内存堆栈。

Most chances to get StackOverflowError are by using [long/infinite] recursions in a recursive functions.

You can avoid Function recursion by changing your application design to use stackable data objects. There are coding patterns to convert recursive codes to iterative code blocks. Have a look at below answeres:

So, you avoid memory stacking by Java for your recessive function calls, by using your own data stacks.

紫南2024-07-31 03:44:13

在某些情况下,您无法捕获 StackOverflowError。

每当你尝试时,你都会遇到新的。 因为它是Java VM。 找到递归代码块是件好事,就像 Andrew Bullock 所说的

On some occasions, you can't catch StackOverflowError.

Whenever you try, you will encounter a new one. Because it is the Java VM. It's good to find recursive code blocks, like Andrew Bullock's said.

独闯女儿国2024-07-31 03:44:13

堆栈跟踪应表明问题的性质。 当您读取堆栈跟踪时,应该有一些明显的循环。

如果这不是一个错误,您需要添加一个计数器或其他一些机制来在递归深入到导致堆栈溢出之前停止递归。

例如,如果您正在使用递归调用处理 DOM 模型中的嵌套 XML,并且 XML 嵌套得太深,则会导致嵌套调用出现堆栈溢出(不太可能,但有可能)。 不过,这必须是相当深的嵌套才会导致堆栈溢出。

The stack trace should indicate the nature of the problem. There should be some obvious looping when you read the stack trace.

If it's not a bug, you need add a counter or some other mechanism to halt the recursion before the recursion goes so deep it causes a stack overflow.

An example of this might be if you're handling nested XML in a DOM model with recursive calls and the XML is nested so deep it causes a stack overflow with your nested calls (unlikely, but possible). This would have to be pretty deep nesting to cause a stack overflow though.

裸钻2024-07-31 03:44:13

正如本线程中的许多人所提到的,造成这种情况的常见原因是递归方法调用未终止。 尽可能避免堆栈溢出,如果您在测试中这样做,您应该在大多数情况下考虑这是一个严重的错误。 在某些情况下,您可以将 Java 中的线程堆栈大小配置为更大以处理某些情况(在本地堆栈存储中管理大型数据集、长递归调用),但这会增加总体内存占用量,从而导致数量问题VM 中可用的线程数。 通常,如果您收到此异常,则该线程和该线程的任何本地数据都应被视为 toast 并且不被使用(即可疑且可能已损坏)。

As mentioned by many in this thread, the common cause for this is a recursive method call that doesn't terminate. Where possible avoid the stack overflow and if you this in testing you should consider this in most cases to be a serious bug. In some cases you can configure the thread stack size in Java to be larger to handle some circumstances ( large data sets being managed in local stack storage, long recursive calls) but this will increase the overall memory footprint which can lead to issues in the number of threads available in the VM. Generally if you get this exception the thread and any local data to this thread should be considered toast and not used( ie suspect and possibly corrupt).

后来的我们2024-07-31 03:44:13

很简单,

查看 StackOverflowError 生成的堆栈跟踪,以便了解它在代码中发生的位置,并使用它来找出如何重写代码,以便它不会递归地调用自身(错误的可能原因),因此它不会再发生了。

StackOverflowErrors 不需要通过 try...catch 子句处理,但它指出了代码逻辑中的基本缺陷,需要您修复。

Simple,

Look at the stack trace that the StackOverflowError produces so you know where in your code it occurs and use it to figure out how to rewrite your code so that it doesn't call itself recursively (the likely cause of your error) so it won't happen again.

StackOverflowErrors are not something that needs to be handled via a try...catch clause but it points to a basic flaw in the logic of your code that needs to be fixed by you.

临走之时2024-07-31 03:44:13

java.lang.Error javadoc:

错误是 Throwable 的子类,它指示合理的应用程序不应尝试捕获的严重问题。 大多数此类错误都是异常情况。 ThreadDeath 错误虽然是“正常”情况,但也是 Error 的子类,因为大多数应用程序不应尝试捕获它。
方法不需要在其 throws 子句中声明在方法执行期间可能抛出但未被捕获的任何 Error 子类,因为这些错误是永远不应该发生的异常情况。

所以,不要这样做。 尝试找出代码逻辑中的问题。 由于无限递归,这种异常经常发生。

java.lang.Error javadoc:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur.

So, don't. Try to find what's wrong in the logic of your code. This exception ocurrs very often because of infinite recursion.

生死何惧2024-07-31 03:44:13

StackOverFlow 错误 - 当您在 Java 中创建方法时,将在堆栈内存中分配一些大小的内存。 如果您在无限循环内创建一个方法,那么将创建“n”次内存分配。 当超出内存分配限制时,就会发生错误。 该错误称为 StackOverFlow 错误。

如果你想避免这个错误,请从一开始就考虑实现时的堆栈内存大小。

StackOverFlow error - when you create a method in Java at the time some size of memory will be allocated in the stack memory. If you create a method inside the infinite loop then a memory allocation will be created 'n' times. When the limit for memory allocation is exceeded then the error will occur. The error is called a StackOverFlow error.

If you want to avoid this error please consider the stack memory size during the implementation from the beginning.

孤独陪着我2024-07-31 03:44:13
/*
Using Throwable we can trap any know error in JAVA..
*/
public class TestRecur {
    private int i = 0;


    public static void main(String[] args) {
        try {
            new TestRecur().show();
        } catch (Throwable err) {
            System.err.println("Error...");
        }
    }

    private void show() {
        System.out.println("I = " + i++);
        show();
    }
}

不过,您可以查看以下链接:http://marxsoftware。 blogspot.in/2009/07/diagnosing-and-resolving.html 来理解代码片段,这可能会引发错误

/*
Using Throwable we can trap any know error in JAVA..
*/
public class TestRecur {
    private int i = 0;


    public static void main(String[] args) {
        try {
            new TestRecur().show();
        } catch (Throwable err) {
            System.err.println("Error...");
        }
    }

    private void show() {
        System.out.println("I = " + i++);
        show();
    }
}

However you may have a look at the link: http://marxsoftware.blogspot.in/2009/07/diagnosing-and-resolving.html to understand the code snippet, which may raise error

£冰雨忧蓝°2024-07-31 03:44:12

我不确定你所说的“处理”是什么意思。

您当然可以捕获该错误:

public class Example {
    public static void endless() {
        endless();
    }

    public static void main(String args[]) {
        try {
            endless();
        } catch(StackOverflowError t) {
            // more general: catch(Error t)
            // anything: catch(Throwable t)
            System.out.println("Caught "+t);
            t.printStackTrace();
        }
        System.out.println("After the error...");
    }
}

但这很可能是一个坏主意,除非您确切地知道自己在做什么。

I'm not sure what you mean with "handle".

You can certainly catch that error:

public class Example {
    public static void endless() {
        endless();
    }

    public static void main(String args[]) {
        try {
            endless();
        } catch(StackOverflowError t) {
            // more general: catch(Error t)
            // anything: catch(Throwable t)
            System.out.println("Caught "+t);
            t.printStackTrace();
        }
        System.out.println("After the error...");
    }
}

but that is most likely a bad idea, unless you know exactly what you are doing.

魂归处2024-07-31 03:44:12

您可能正在进行一些无限递归。

即,一个一遍又一遍地调用自身的方法

public void sillyMethod()
{
    sillyMethod();
}

来处理这个问题是修复您的代码,以便递归终止而不是永远继续。

You probably have some infinite recursion going on.

I.e. a method that calls itself over and over

public void sillyMethod()
{
    sillyMethod();
}

One to handle this is to fix your code so that the recursion terminates instead of continuing forever.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文