如何在Java中处理StackOverflowerr?

如何在Java中处理StackOverflowerr?,java,exception,jakarta-ee,stack-overflow,Java,Exception,Jakarta Ee,Stack Overflow,如何在Java中处理StackOverflowerError?您可能正在进行一些无限递归 即,一个反复调用自身的方法 public void sillyMethod() { sillyMethod(); } 处理这个问题的一个方法是修复代码,使递归终止而不是永远继续。我想你不能——或者至少取决于你使用的jvm。堆栈溢出意味着您没有空间存储局部变量和返回地址。如果您的jvm执行某种形式的编译,那么jvm中也存在堆栈溢出,这意味着您无法处理或捕获它。jvm必须终止 有一种方法可以创建一个允

如何在Java中处理
StackOverflowerError

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

即,一个反复调用自身的方法

public void sillyMethod()
{
    sillyMethod();
}

处理这个问题的一个方法是修复代码,使递归终止而不是永远继续。

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

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


我还没有用jvm测试这种行为,但在.net中,您无法处理stackoverflow。即使试抓也无济于事。由于java和.net依赖于相同的概念(带有jit的虚拟机),我怀疑java的行为会是相同的。NET中存在stackoverflow异常表明,可能存在某些vm使程序能够捕获它,但正常情况下不会。堆栈跟踪应指示问题的性质。在读取堆栈跟踪时,应该有一些明显的循环

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


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

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

我不知道你说的“把手”是什么意思

您肯定会发现这个错误:

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...");
    }
}
但这很可能是个坏主意,除非你确切知道自己在做什么。

请看一看这篇文章。摘录:

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

假设你唱的是弗雷尔·雅克这首歌,除了你唱的每一节都比前一节高出几个音调。最终,你将达到你的歌唱范围的最高点,具体发生在哪里取决于你的声音极限与旋律的对位。在旋律中,前三个音符各有一个新的“记录高点”(即,这些音符比迄今为止唱过的任何其他音符都高),第三个音阶的三个音符出现了新的记录高点,第五个音阶的第二个音符出现了最后的记录高点

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

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


您可能希望查看JVM是否支持“-Xss”选项。如果是这样,您可能希望尝试将其设置为512k(32位Windows和Unix下的默认值为256k),并查看这是否有任何作用(除了让您在StackOverflowException之前坐得更久)。请注意,这是一个每个线程的设置,因此如果您有很多线程在运行,您可能还需要增加堆设置。

简单

查看StackOverflowerError生成的堆栈跟踪,这样您就可以知道它发生在代码中的什么地方,并使用它来找出如何重写代码,这样它就不会递归地调用自己(这可能是错误的原因),这样就不会再发生


StackOverflowers错误不需要通过try…catch子句处理,但它指出了代码逻辑中的一个基本缺陷,需要您修复。

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

所以,不要。试着找出代码逻辑中的错误。这种例外情况经常发生,因为它是无限的
// 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())); 
    }
}
/*
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();
    }
}