什么会导致java.lang.StackOverflowError
?我得到的堆栈打印输出根本不是很深(只有 5 种方法)。
12 回答
Check for any recusive calls for methods. Mainly it is caused when there is recursive call for a method. A simple example is
public static void main(String... args) {
Main main = new Main();
main.testMethod(1);
}
public void testMethod(int i) {
testMethod(i);
System.out.println(i);
}
Here the System.out.println(i); will be repeatedly pushed to stack when the testMethod is called.
JVM 的(可选)参数之一是堆栈大小。这是-Xss。我不知道默认值是什么,但如果堆栈上的东西总量超过该值,您将收到该错误。
通常,无限递归是造成这种情况的原因,但如果您看到这种情况,您的堆栈跟踪将超过 5 帧。
尝试添加一个 -Xss 参数(或增加一个的值),看看这是否会消失。
什么是java.lang.StackOverflowError
抛出该错误java.lang.StackOverflowError
表明应用程序的堆栈已用尽,这是由于深度递归,即您的程序/脚本递归太深。
细节
StackOverflowError
extends类,VirtualMachineError
表明 JVM 已经或已经耗尽资源并且无法进一步操作。VirtualMachineError
which 扩展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 应用程序调用函数调用时,会在调用堆栈上分配一个堆栈帧。包含被调用方法的参数、它的本地参数和方法的返回地址。返回地址表示被调用的方法返回后程序继续执行的执行点。如果没有空间用于新的堆栈帧,则由 Java 虚拟机 (JVM) 抛出。stack frame
StackOverflowError
可能耗尽 Java 应用程序堆栈的最常见情况是递归。在递归中,方法在执行期间调用自身。Recursion
最强大的通用编程技术之一,但必须谨慎使用,以免StackOverflowError
发生这种情况。
参考
实际导致 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,它通常很容易解决。
理论上,也有可能在没有递归的情况下发生堆栈溢出,但在实践中,这似乎是一个相当罕见的事件。
Hibernate 用户解析数据时的解决方案:
我遇到了这个错误,因为我正在解析一个映射在两边的对象列表,@OneToMany
并@ManyToOne
使用杰克逊解析到 json,这导致了无限循环。
如果你处于同样的情况,你可以通过使用@JsonManagedReference
和@JsonBackReference
注释来解决这个问题。
来自 API 的定义:
JsonManagedReference(https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html):
Annotation 用于表示被注释的属性是字段之间双向链接的一部分;并且它的作用是“父”(或“转发”)链接。属性的值类型(类)必须有一个使用 JsonBackReference 注释的兼容属性。链接被处理,使得被这个注解注解的属性被正常处理(正常序列化,反序列化没有特殊处理);需要特殊处理的是匹配的反向引用
JsonBackReference:(https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html):
用于指示关联属性是字段之间双向链接的一部分的注释;并且它的作用是“子”(或“后”)链接。属性的值类型必须是 bean:不能是 Collection、Map、Array 或枚举。处理链接,使得使用此注解注解的属性不被序列化;并且在反序列化期间,它的值设置为具有“托管”(转发)链接的实例。
例子:
所有者.java:
@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;
汽车.java:
@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;
另一种解决方案是使用@JsonIgnore
它只会将 null 设置为该字段。
当 Java 应用程序调用函数调用时,会在调用堆栈上分配一个堆栈帧。堆栈帧包含被调用方法的参数、其本地参数和方法的返回地址。
返回地址表示被调用的方法返回后程序继续执行的执行点。如果没有空间用于新的堆栈帧,则Java 虚拟机 (JVM)会抛出StackOverflowError。
可能耗尽 Java 应用程序堆栈的最常见情况是递归。
请看一看
如何解决 StackOverflowError
我用 hibernate 创建了一个程序,在其中我创建了两个 POJO 类,它们都具有彼此的对象作为数据成员。当在主要方法中我试图将它们保存在数据库中时,我也得到了这个错误。
发生这种情况是因为两个类都相互引用,因此创建了一个导致此错误的循环。
因此,请检查您的程序中是否存在任何此类关系。
当线程堆栈的大小继续增长直到达到最大限制时,可能会发生堆栈溢出异常。
调整堆栈大小(Xss 和 Xmso)选项...
我建议您查看此链接: http ://www-01.ibm.com/support/docview.wss?uid= swg21162896 StackOverflowError 有很多可能的原因,您可以在链接中看到......
我有同样的问题
角色.java
@ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY,cascade = CascadeType.ALL)
Set<BusinessUnitMaster> businessUnits =new HashSet<>();
BusinessUnitMaster.java
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
name = "BusinessUnitRoles",
joinColumns = {@JoinColumn(name = "unit_id", referencedColumnName = "record_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "record_id")}
)
private Set<Role> roles=new HashSet<>();
问题是,当您创建 BusinessUnitMaster 和 Role 时,您必须为 RoleService.java 保存双方的对象
roleRepository.save(role);
对于 BusinessUnitMasterService.java
businessUnitMasterRepository.save(businessUnitMaster);
在我的情况下,我必须覆盖子类中的 equals 和 hashcode 类方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MyClass)) return false;
return id != null && id.equals(((MyClass) o).getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
此处参考:vladmihalcea 文章
就我而言,我有两个活动。在第二个活动中,我忘记将 super 放在 onCreate 方法上。
super.onCreate(savedInstanceState);
在我的情况下toString导致实体类中的异常检查您的系统日志它将帮助您解决异常