StackOverFlow 错误:原因和解决方案

想要详细了解 JVM 项目中 StackOverFlowError 的潜在原因和解决方案吗?查看这篇文章以了解更多信息。

StackOverFlowError是常见的JVM 错误之一。在这篇博文中,我们将了解线程堆栈的内部机制、触发StackOverFlowError此错误的原因以及解决此错误的潜在解决方案。

为了更深入地了解StackOverFlowError,让我们回顾一下这个简单的程序:

public class SimpleExample {

      public static void main(String args[]) {

            a()
      }

      public static void a() {

            int x = 0;
            b();
      }

      public static void b() {

            Car y = new Car();
            c();
      }

      public static void c() {

            float z = 0f;
      System.out.println("Hello");
      }
}

这个程序非常简单,执行代码如下:网址:yii666.com<

  1.  main()首先调用方法文章来源地址https://www.yii666.com/learning/java/305.html

  2.  main() 方法调用a() 方法。在方法内部a() ,整型变量“x”被初始化为值 0。网址:yii666.com

  3.  a() 方法依次调用b()方法。在方法内部b() ,构造 Car 对象并将其分配给变量“y”。

  4.  b() 方法依次调用该c()方法。在该c()方法内部,浮点变量“z”被初始化为值 0。

现在,让我们回顾一下执行上述简单程序时幕后发生的情况。应用程序中的每个线程都有自己的堆栈。每个堆栈有多个堆栈帧。线程将其正在执行的方法、原始数据类型、对象指针以及返回值按照它们执行的顺序添加到其堆栈帧中。


线程的堆栈帧

图 1:线程的堆栈帧


步骤#1: main() 方法被推入应用程序线程的堆栈中。

步骤#2: a() 方法被推入应用程序线程的堆栈中。在a() 方法中,原始数据类型“int”定义为值 0 并分配给变量 x。该信息也被推送到同一堆栈帧中。请注意,这两个数据(即“0”和变量“x”)都被推入线程的堆栈帧中。

步骤#3: b() 方法被推入线程的堆栈。在该b() 方法中,创建了 Car 对象并将其分配给变量“y”。这里需要注意的一个关键点是“Car”对象是在堆中创建的,而不是在线程的堆栈中创建的。只有 Car 对象的引用(即 y)存储在线程的堆栈帧中。

步骤#4: c() 方法被推入线程的堆栈中。在c() 方法中,原始数据类型“float”定义为值 0f 并分配给变量 z。该信息也被推送到同一堆栈帧中。请注意,这两个数据(即“0f”和变量“z”)都被推入线程的堆栈帧中。

每个方法执行完成后,该方法和存储在堆栈帧中的变量/对象指针将被删除,如图 2 所示。

执行方法后线程的堆栈帧

图 2:执行方法后线程的堆栈帧

是什么原因造成的StackOverflowError?

正如您所看到的,线程的堆栈存储它正在执行的方法、原始数据类型、变量、对象指针和返回值。所有这些都会消耗内存。如果线程的堆栈大小超出了分配的内存限制,则会StackOverflowError 抛出异常。让我们看一下下面的错误程序,它将导致  StackOverflowError

public class SOFDemo {
    public static void a() {
        // Buggy line. It will cause method a() to be called infinite number of times.
        a();
    }
    public static void main(String args[]) {
        a();
    }
}

在这个程序中,main() 方法调用a() 方法。a() 方法递归调用自身。此实现将导致  a() 方法被无限次调用。在这种情况下,a() 方法将被无限次添加到线程的堆栈帧中。因此,经过几千次迭代后,将超出线程的堆栈大小限制。一旦超出堆栈大小限制,将导致  StackOverflowError

Exception in thread "main" java.lang.StackOverflowError
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
    at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)

StackOverflowError 进展

图 3:StackOverflowError 进展

有什么解决办法StackOverflowError

有几个策略需要解决  StackOverflowError

1. 修复代码

由于非终止递归调用(如上例所示),线程堆栈大小可能会增长到很大。在这些情况下,您必须修复导致递归循环的源代码。当StackOverflowError抛出时,它将打印递归执行的代码的堆栈跟踪。此代码是开始调试和解决问题的良好指针。在上面的例子中,就是a()  方法。

2. 增加线程堆栈大小 ( -Xss)

需要增加线程的堆栈大小可能有合理的原因。也许线程必须执行大量方法或线程正在执行的方法中/创建的大量局部变量?在这种情况下,您可以使用 JVM 参数增加线程的堆栈大小:-Xss。启动应用程序时需要传递此参数。例子:

-Xss2m

这会将线程的堆栈大小设置为 2 mb。

这可能会带来一个问题:默认线程的堆栈大小是多少?默认线程堆栈大小因操作系统、Java 版本和供应商而异。


JVM版本

线程堆栈大小

Sparc 32 位 JVM

512k

Sparc 64 位 JVM

1024k

x86 Solaris/Linux 32 位 JVM

320K文章来源地址:https://www.yii666.com/learning/java/305.html

x86 Solaris/Linux 64 位 JVM

1024K

Windows 32 位 JVM

320K

Windows 64 位 JVM

1024K

3. 具有自定义堆栈大小的线程

另一种缓解方法StackOverflowError是利用 Java 的线程构造函数,它允许您为各个线程指定自定义堆栈大小。这个构造函数可以在Java 文档(https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#Thread-java.lang.ThreadGroup-java.lang.Runnable-java.lang.String-long-)中找到。虽然此选项提供了为每个线程设置特定堆栈大小的灵活性,但请务必注意,其有效性可能因不同平台而异。文章地址https://www.yii666.com/learning/java/305.html

Thread thread = new Thread(null, runnable, "CustomThread", customStackSize);
thread.start();

然而,重要的是要意识到设置参数的影响在所有平台上stackSize可能并不
一致。Java文档指出:“在某些平台上,stackSize 参数的值可能没有任何影响虚拟机可以自由地将stackSize参数视为建议。”

在我们自己的测试中,我们发现使用自定义堆栈大小调用此构造函数对 Windows 和某些其他平台没有影响。跨平台缺乏一致性使得该选项作为通用解决方案不太可靠。作为最佳实践,建议选择在所有平台上一致工作的解决方案,以确保应用程序的稳定性和可靠性。


其他相关文章
    领支付宝红包赞助服务器费用
    如何防止 PHP 中的 SQL 注入?
    微信公众号:小猪波罗蜜
    关注公众号,回复999,可联系站长解答疑问哦。每天分享更多有趣的事儿,有趣有料!
    99人已关注

    觉得文章有用就打赏一下文章作者

    支付宝扫一扫打赏

    微信图片_20190322181744_03.jpg

    微信扫一扫打赏

    请作者喝杯咖啡吧~

    支付宝扫一扫领取红包,优惠每天领

    二维码1

    zhifubaohongbao.png

    二维码2

    zhifubaohongbao2.png