如何处理 StackOverflowError 在Java?

有帮助吗?

解决方案

我不知道你的意思是"处理"。

你当然可以赶上的错误:

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.e。一个方法,要求本身过

public void sillyMethod()
{
    sillyMethod();
}

一个来处理这个是来修你的代码,以便递归终止,而不是继续永远.

看看 雷蒙德*陈's post 在调试一堆溢出,要重点放在重复递归的部分.一提:

如果你去打猎通过你的缺陷跟踪数据库试图看看这是否是一个已知的问题或不,搜索顶部的功能在该堆不可能找到什么有趣的。那是因为堆溢出往往发生在一个随机的点在递归;每个堆栈溢出表面上看起来不同是从其他每一个即使他们是同一堆溢出。

假设你唱这首歌 见雅克, ,除了,你唱的每一节的几个调高于前一个。最终,你就会到达顶部你唱歌的范围,并精确地说那里发生这种情况取决于在哪里你的声限制行对付的旋律。在旋律,第三笔记每一个新的"记录高"(即,注意到高于任何其他的注意唱迄今为止),以及新的创纪录水平出现在三个注意到的第三项措施,并最终的最高记录中的第二份说明的第五措施。

如果旋律表示的程序的堆使用情况,一堆溢出可能发生在任何这些五个地点的程序的执行。换句话说,相同的基础的失控递归(音乐表示由一个高唱的旋律)可以体现在五个不同的方式。将"递归"在这个类比是相当快的,只是八条之前的循环重复。在现实生活中,将循环可以相当长,导致几十个潜在的点在哪里堆溢出,可能体现自身。

如果你正面临着一堆溢,那么,你想要忽略的顶部叠,因为这只是侧重于具体的注意,超出了你的声的范围内。你真的想找到整个旋律,因为这是什么共同所有的叠充溢着相同的根本原因。

你可能想看看如果"-Xss"的选项是支持你的JVM。如果是这样,你可能要试图设置为一个值的512k(默认是256k下的32位Windows和Unix),看看是否能做任何事(除了让你坐的时间,直到你StackOverflowException).注意,这是每一个线程设置,所以,如果你已经有了很多线程的运行,你也可能想碰你的堆的设置。

正确的答案是一个已经给出。你有可能一)有一个代码中的缺陷导致一个无限的递归,这通常是很容易诊断和修复,或者b)有代码这可能会导致非常深刻的递归例如递归穿越不平衡的二进制树。在后一种情况下,需要改变你的代码不是分配上的信息叠(即不recurse)但要,而不是分配它在堆。

例如,对于一个不平衡的树历,你可以存储节点,将需要重新加以讨论的一堆数据结构。对一个为了穿越你会环左分支机构推动的各个节点因为你与它直到你打叶,你会处理,然后流行的节点的堆、处理,然后重新启动你的循环有的权利,儿童(通过只是你的循环变为正确的节点。) 这将使用一定数量的堆通过移动的一切,是在堆堆堆的数据结构。堆通常是更加丰富于堆叠。

为什么,通常是一个非常糟糕的主意,但是有必要的情况下存储器的使用是非常受限,可以使用的指针逆转。在这种技术,编码的成堆的结构你是穿越,并通过重新使用的链接,你是穿过,你可以这样做没有或明显较少的额外存储器。使用上述实例中,而不是推动节点的时候,我们的循环,我们只需要记住我们的立即父母,并且在每次迭代,我们设置了链接,我们走到目前的父母然后当父母的节点我们离开。当我们得以一叶,我们处理它,然后转到我们的父母然后我们有一个难题。我们不知道是否正确左分支,处理这个节点,并继续用正确的分支,或纠正的权利支和去我们的父母。因此,我们需要分配一个额外的信息,因为我们迭代。通常,低级实现这种技术,这一点将被保存在指本身导致不附加的存储器和常量存储器的整体。这不是一个选项,但它可能可以松鼠走这点领域用于其它的事情。在最坏的情况下,这仍然是至少32或64次量减少存储需要。当然,这种算法是非常容易得到错误的完全令人困惑的结果,并将提出全然破坏并发。所以这是几乎从来没有值得维持的噩梦,除了在那里分配的记忆是站不住脚的。典型的例子是垃圾收集器,其中的算法,这样是常见的。

我真正想说的,不过,是时候你也许想要处理StackOverflowError.即提供尾呼吁消除在JVM。一种方法是使用蹦床的风格,而不是执行一个尾叫你回nullary程序的对象,或者如果你是刚刚返回值的返回。[注:这需要一些装置的说功能返回或B。在爪哇,可能是最轻的方式来做到这一点是返回的一种类型通常并把其作为一个例外。] 然后当你呼叫一个方法,就需要做,同时循环调nullary程序(其中将自己返回nullary过程或价值),直到你得到一个价值。一个无穷无尽的循环将成为一个同时循环,不断迫使程序的对象返回程序的对象。本效益的蹦床式是,它只使用恒定因素更多的堆比你想使用一个执行该适当地消除所有尾巴的呼吁,它使用的正常Java堆非尾呼吁,翻译简单,它只生长的代码由(繁琐)恒的因素。缺点是分配上的对象每个方法的呼吁(它将立即成为垃圾)和消耗这些对象涉及一对夫妇的间接调用每尾的呼吁。

理想的做法是,从来没有分配这些nullary程序或其他任何东西放在第一位,而这正是尾呼吁消除将完成。工作有什么Java提供不过,我们可以做什么运行的代码作为正常的,只有使这些nullary程序,当我们跑出来的堆。现在,我们仍然分配那些无用的框架,但我们这样做叠,而不是堆和释放他们在散装,此外,我们的呼吁是正常的直接Java话。最简单的方法来描述这种转变是第一重写所有多呼声明的方法进入的方法有两个电话发言,即f-g-h(){f();g();h();}变成f-g-h(){f();gh();}和gh(){g();h();}.为了简单起见,我会承担的所有方法都结束在结尾呼吁,这可以安排只是包装剩余的一个方法成为一个单独的方法,但在实践中,你会想处理这些直接。之后这些变化我们有三个情况下,任何一个方法具有零呼吁在这种情况下,没有什么可以做的,或者它有一个(尾巴)称,在这种情况下,我们把它包装在一试-抓住框在同我们会尾呼吁在这两个呼吁的情况。最后,它可以有两个电话,一个非尾翼和尾呼吁,在这种情况下,我们应用以下转型示例(使用C#'s 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()call)没有处理弹例外,该例外会飞过他们绕这些(不必要的)框架从栈。非尾呼吁抓弹例外,重新引发他们的剩余码加入。这将不妨堆的所有方式达到的最高水平,消除尾呼吁的框架,但记住不尾呼吁框架在nullary程序。当我们终于执行过程中的弹异常在顶层,我们将重建所有的非尾呼吁的框架。在这一点上,如果我们立刻跑出来的堆再次,然后,由于我们没重装StackOverflowError处理程序,它将未捕获的,为希望,因为我们真是堆。如果我们得到一个小小的一步,一个新的StackOverflowError将安装适当的。此外,如果我们做得进展,但后来做完的堆再次,没有任何益处重新展开框架,我们已经开卷,所以我们安装新的顶级处理程序使得堆叠将只能解开了他们。

最大的问题,这种做法是,你可能会想要呼叫正常Java方法和可能具有任意地点的堆空间时这样做,所以他们可能有足够的空间来开始,但不完你不可能恢复他们在中间。至少有两个解决方案。第一是船舶所有这些工作的一个单独的线程,这将有它自己的堆。这是相当有效的和相当容易并且不会引入任何并发(除非你想让它。) 另一个选择是只是故意妨堆话之前的任何正常Java方法通过简单地投掷StackOverflowError立即在他们之前。如果它仍然运行的堆空间当你的简历,然后你拧开始。

类似的事情可以做,以使延续的时间太长。不幸的是,这一转变是不是真的可以忍受这样做一方面,可能是边缘型的语言等C#或者拉斯卡拉.因此,转换,这样往往可以通过语言,目标JVM并不由人。

我猜你不能-或至少取决于jvm你使用。堆溢意味着,你有没有储存地的变量和返回的地址.如果你jvm不某种形式的汇编、你们的计算器在jvm以及这意味着,你不能处理它或是抓住它。Jvm已经终止。

有可能是一种方式来创建一个jvm,允许对这种行为,但这将是缓慢的。

我没有测试过的行为与jvm,但在。净你就不能处理的计算器.甚至尝试追赶不会帮助。由于java和。净依赖相同的概念(虚拟机jit)我怀疑java会的行为相同。存在的一个计算器异常。净建议,可能有一些虚拟机会启用的程序抓住它,通常不会虽然。

大多数机会得到 StackOverflowError 是通过使用[长期/无限]递归在递归功能。

你可以避免递归功能通过改变你的应用程序的设计使用可堆叠的数据的对象。有编码模式转递归码迭代码块。看看在下面点击:

因此,可以避免存堆放过Java你的隐性功能的电话,通过使用自己的数据层。

堆跟踪应该说明的性质的问题。应该有一些明显的循环,当你读这堆踪。

如果它是不是一个错误,你需要添加一个计数器或其他一些机制来制止递归之前递归去如此之深,它将导致一堆溢出。

这样的一个例子可能如果你在处理嵌套DOM XML模型用递归的电话和XML套如此之深,它将导致一堆溢出你的套话(不可能的,但可能)。这将是漂亮的深嵌套引起一堆溢出,虽然。

正如许多在这个线程,常见原因为这是一个递归的方法调,这并不终止。尽可能避免堆溢出并且如果你这个测试,你应该考虑这在大多数情况下是一个严重的错误。在某些情况下可以配置的线堆尺寸在Java要大于处理某些情况下(大数据集的管理在本地堆储存、长递电话),但这将增加总内存占其可能导致问题的数量在线提供虚拟机。一般来说,如果你得到这个例外线和任何地方的数据为这个线程应考虑面包和不使用(即怀疑,并可能损坏).

简单,

看看这堆跟踪,StackOverflowError生产的所以你知道在哪里在你的代码发生,并用它来弄清楚如何重写代码,以便它不会叫本身递归(可能因为你的错误),所以它不会再次发生。

StackOverflowErrors是不是需要处理通过一试...抓住条款,但它指向的一个基本缺陷逻辑的代码,需要加以固定。

java。郎。错如果是的话,为什么不试:

错误的一个子类抛出 表示严重问题,这些问题的一个合理的应用不应该试图抓住.大多数这样的错误异常情况。该ThreadDeath错误,虽然一个"正常"条件,也是一类错误,因为大多数的应用不应该试图抓住它。一方法不需要声明其引发的条款的任何子类的错误,可能会被抛在执行的方法,但是没有抓到,由于这些错误的异常条件下,永远不应该发生。

所以,不要。试图找到什么错误的逻辑。这一例外ocurrs常常是因为无限递归。

在一些场合,可以抓不住stackoverflowerror.只要你尝试,你会遇到新的。因为是java vm。这是很好的找到递归码块一样 安德鲁*布洛克就是说.

/*
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 要了解代码段,这可能会引起错误

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top