什么导致java.lang.StackOverflower错误

fruv7luv  于 2021-07-06  发布在  Java
关注(0)|答案(9)|浏览(423)

什么会导致 java.lang.StackOverflowError ? 我得到的堆栈打印输出不是很深(只有5种方法)。

yduiuuwa

yduiuuwa1#

当线程堆栈继续增大直到达到最大限制时,可能会发生堆栈溢出异常。
正在调整堆栈大小(xss和xmso)选项。。。
我建议你看看这个链接:http://www-01.ibm.com/support/docview.wss?uid=swg21162896 StackOverflower错误有很多可能的原因,正如您在链接中看到的。。。。

hsvhsicv

hsvhsicv2#

检查方法的任何重复调用。它主要是在对方法进行递归调用时产生的。一个简单的例子是

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时重复推送到堆栈中。

z5btuh9x

z5btuh9x3#

我用hibernate创建了一个程序,在这个程序中我创建了两个pojo类,它们都有一个互为数据成员的对象。在main方法中,当我试图将它们保存到数据库中时,我也遇到了这个错误。
这是因为两个类都在互相引用,因此创建了一个导致此错误的循环。
所以,检查你的程序中是否存在这样的关系。

ego6inou

ego6inou4#

我有两个活动。在第二个活动中,我忘了在oncreate方法上加super。

super.onCreate(savedInstanceState);
f87krz0w

f87krz0w5#

什么是java.lang.StackOverflower

错误 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 frame 包含被调用方法的参数、其本地参数和方法的返回地址。返回地址表示执行点,在调用的方法返回后,程序将从该点继续执行。如果没有新堆栈帧的空间,则 StackOverflowError 由java虚拟机(jvm)抛出。
可能耗尽java应用程序堆栈的最常见情况是递归。在递归中,方法在执行期间调用自身。 Recursion 最强大的通用编程技术之一,但必须谨慎使用,以便 StackOverflowError 必须避免。

参考文献

java文档
堆栈溢出错误

iqih9akk

iqih9akk6#

jvm的一个(可选)参数是堆栈大小。是-xss。我不知道默认值是什么,但如果堆栈上的内容总量超过该值,您将得到该错误。
一般来说,无限递归是造成这种情况的原因,但是如果您看到了这一点,那么堆栈跟踪的帧数将超过5帧。
尝试添加一个-xss参数(或增加一个参数的值),看看这是否会消失。

hpcdzsge

hpcdzsge7#

实际上导致java.lang.StackOverflower错误的原因通常是无意的递归。对我来说,经常是当我打算调用一个超级方法来替代过度的方法时。例如在这种情况下:

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),以便被调用方法可以访问参数,并且当被调用方法完成时,可以在调用之后继续执行。但是由于我们递归地调用这个.accelerate(acceleration,maxvelocity)(当方法调用自身时,递归是松散的。有关更多信息,请参阅http://en.wikipedia.org/wiki/recursion_(计算机科学)我们处于一种被称为无限递归的情况,我们不断地将参数和返回地址堆积在调用堆栈上。因为调用堆栈的大小是有限的,所以我们最终会耗尽空间。调用堆栈上的空间不足称为溢出。这是因为我们试图使用比现有的堆栈空间更多的堆栈空间,而数据实际上会溢出堆栈。在java编程语言中,这会导致运行时异常java.lang.stackoverflow并立即停止程序。
上面的例子有点简化(虽然发生在我身上的事情比我想承认的要多),同样的事情可能会以一种更全面的方式发生,使得追踪起来有点困难。然而,一般来说,一旦发生堆栈溢出,通常很容易解决。
从理论上讲,也有可能在没有递归的情况下发生堆栈溢出,但在实践中,这似乎是一个相当罕见的事件。

u4dcyp6a

u4dcyp6a8#

当java应用程序调用函数调用时,会在调用堆栈上分配一个堆栈帧。堆栈框架包含被调用方法的参数、其本地参数和方法的返回地址。
返回地址表示执行点,在调用的方法返回后,程序将从该点继续执行。如果没有空间容纳新的堆栈帧,则由java虚拟机(jvm)抛出stackoverflowerror。
可能耗尽java应用程序堆栈的最常见情况是递归。
请看一看

如何解决堆栈溢出错误

gopyfrb3

gopyfrb39#

hibernate用户解析数据时的解决方案:
我有这个错误,因为我正在解析Map在两边的对象列表 @OneToMany 以及 @ManyToOne 使用jackson生成json,这导致了一个无限循环。
如果您处于相同的情况,您可以使用 @JsonManagedReference 以及 @JsonBackReference 注解。
api中的定义:
jsonmanagedreference公司(https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/jsonmanagedreference.html) :
注解用于指示被注解的属性是字段之间双向链接的一部分;它的角色是“父”(或“转发”)链接。属性的值类型(类)必须有一个用jsonbackreference注解的兼容属性。处理链接时,使用此注解注解的属性将正常处理(正常序列化,没有反序列化的特殊处理);匹配的back引用需要特殊处理
jsonbackreference:(https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/jsonbackreference.html):
用于指示关联属性是字段之间双向链接的一部分的注解;它的角色是“子”(或“后”)链接。属性的值类型必须是bean:它不能是集合、Map、数组或枚举。处理链接时,使用此注解注解的属性不会序列化;在反序列化过程中,它的值被设置为具有“托管”(前向)链接的示例。
例子:
所有者.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。

相关问题