什么可以导致java.lang.StackOverflowError
?我得到的堆栈打印输出不是很深(只有5种方法).
检查是否有任何方法的重复调用.主要是当有一个方法的递归调用时引起.一个简单的例子是
public static void main(String... args) { Main main = new Main(); main.testMethod(1); } public void testMethod(int i) { testMethod(i); System.out.println(i); }
这里是System.out.println(i); 在调用testMethod时,将反复推送到堆栈.
JVM的(可选)参数之一是堆栈大小.这是-Xss.我不知道默认值是什么,但如果堆栈上的东西总量超过该值,您将得到该错误.
通常,无限递归是导致这种情况的原因,但是如果你看到了这一点,你的堆栈跟踪将有超过5帧.
尝试添加-Xss参数(或增加一个值)以查看它是否消失.
实际上导致java.lang.StackOverflowError的原因通常是无意的递归.对我来说,通常我打算为覆盖方法调用超级方法.比如在这种情况下:
public class Vehicle { public void accelerate(float acceleration, float maxVelocity) { // set the acceleration } } public class SpaceShip extends Vehicle { @Override public void accelerate(float acceleration, float maxVelocity) { // update the flux capacitor and call super.accelerate // oops meant to call super.accelerate(acceleration, maxVelocity); // but accidentally wrote this instead. A StackOverflow is in our future. this.accelerate(acceleration, maxVelocity); } }
首先,了解调用函数时幕后发生的事情很有用.调用方法的参数和地址被推送到堆栈上(参见http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management),以便被调用的方法可以访问参数,这样当被调用的方法完成后,执行可以在调用后继续.但是因为我们以递归方式调用this.accelerate(acceleration,maxVelocity)(当方法调用自身时递归是松散的.有关更多信息,请参阅http://en.wikipedia.org/wiki/Recursion_(computer_science)我们处于一种称为无限递归的情况,我们不断地在调用堆栈上堆积参数和返回地址.由于调用堆栈的大小有限,我们最终会耗尽空间.调用堆栈上的空间耗尽称为溢出.这是因为我们试图使用比我们更多的堆栈空间,并且数据实际上溢出了堆栈.在Java编程语言中,这会导致运行时异常java.lang.StackOverflow并立即停止该程序.
上面的例子有点简化(虽然它比我想承认的更多.)同样的事情可能发生在一个更圆的方式使它更难以追查.但是,一般情况下,一旦发生,StackOverflow通常很容易解决.
从理论上讲,堆栈溢出也可能没有递归,但在实践中,它似乎是一个相当罕见的事件.
java.lang.StackOverflowError
java.lang.StackOverflowError
由于深度递归(即您的程序/脚本递归太深)而引发该错误,以指示应用程序堆栈已耗尽。
该StackOverflowError
扩展VirtualMachineError
类这表明JVM已经或有资源的耗尽而无法进一步操作。将VirtualMachineError
它扩展了Error
类用于指示那些严重的问题,应用程序不应该捕获。方法可能不会在其throw
子句中声明此类错误,因为这些错误是异常情况,从未发生过。
Minimal, Complete, and Verifiable Example
:
package demo; public class StackOverflowErrorExample { public static void main(String[] args) { StackOverflowErrorExample.recursivePrint(1); } public static void recursivePrint(int num) { System.out.println("Number: " + num); if(num == 0) return; else recursivePrint(++num); } }
Number: 1 Number: 2 . . . Number: 8645 Number: 8646 Number: 8647Exception in thread "main" java.lang.StackOverflowError at java.io.FileOutputStream.write(Unknown Source) at java.io.BufferedOutputStream.flushBuffer(Unknown Source) at java.io.BufferedOutputStream.flush(Unknown Source) at java.io.PrintStream.write(Unknown Source) at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source) at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source) at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source) at java.io.OutputStreamWriter.flushBuffer(Unknown Source) at java.io.PrintStream.newLine(Unknown Source) at java.io.PrintStream.println(Unknown Source) at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11) at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16) . . . at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
当Java应用程序调用函数调用时,将在调用stack上分配一个堆栈框架。该包含调用的方法,它的本地参数和方法的返回地址的参数。返回地址表示执行点,从该执行点开始,在调用的方法返回后,程序将继续执行。如果没有空间用于新的堆栈框架,则Java虚拟机(JVM)会抛出该异常。stack frame
StackOverflowError
可能耗尽Java应用程序堆栈的最常见情况是递归。作为递归,方法在执行过程中会自行调用。Recursion
一种最强大的通用编程技术,但必须谨慎使用,以免StackOverflowError
出现这种情况。
Java文档
StackOverflowError