java.lang.StackOverflowError——如何解決StackOverflowError錯誤

原文鏈接:https://examples.javacodegeeks.com/java-basics/exceptions/java-lang-stackoverflowerror-how-to-solve-stackoverflowerror/

StackOverflowError在程序??臻g耗盡時拋出,通常是深度遞歸導致。StackOverflowError繼承了VirtualMachineError類,后者表示JVM已被破壞或資源耗盡。更進一步,VirtualMachineError繼承自Error類,應用程序不應該捕獲這種嚴重的錯誤。不要再throw語句里面拋出這樣的錯誤,因為這些錯誤是不應該發(fā)生的異常條件。StackOverflowError從Java 1.0版本就已存在。

StackOverflowError構(gòu)造函數(shù)

StackOverflowError()StackOverflowError(String s),后者的String參數(shù)指明了拋出錯誤的類名。

The StackOverflowError in Java

當一個函數(shù)被Java程序調(diào)用的時候,就會在調(diào)用棧上分配棧幀。棧幀包含被調(diào)用函數(shù)的參數(shù)、局部變量和返回地址。返回地址指示了當函數(shù)執(zhí)行完畢之后下一步該執(zhí)行哪里。如果創(chuàng)建棧幀時沒有內(nèi)存空間,JVM就會拋出StackOverflowError。

最常見的耗盡Java棧的案例是遞歸。在遞歸操作中,函數(shù)執(zhí)行時會調(diào)用自己。使用遞歸要小心,以免拋出StackOverflowError錯誤。如下的例子演示了遞歸如何拋出StackOverflowError:

public class StackOverflowErrorExample {
    
    public static void recursivePrint(int num) {
        System.out.println("Number: " + num);
        
        if(num == 0)
            return;
        else
            recursivePrint(++num);
    }
    
    public static void main(String[] args) {
        StackOverflowErrorExample.recursivePrint(1);
    }
}

如果num為0,遞歸就會終止,但是這里一開始傳入1,每次遞歸都自增1,遞歸永遠不會終止。
使用-Xss1M參數(shù)指定線程??臻g大小為1M,這個例子的執(zhí)行結(jié)果如下:

Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
        at java.io.PrintStream.write(PrintStream.java:480)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
        at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
        at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
        at java.io.PrintStream.write(PrintStream.java:527)
        at java.io.PrintStream.print(PrintStream.java:669)
        at java.io.PrintStream.println(PrintStream.java:806)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        ...

More about the StackOverflowError in Java

下面的例子演示了類之間有循環(huán)關(guān)系時的風險。

class A {
    private int aValue;
    private B bInstance = null;
    
    public A() {
        aValue = 0;
        bInstance = new B();
    }
    
    @Override
    public String toString() {
        return "";
    }
}

class B {
    private int bValue;
    private A aInstance = null;
    
    public B() {
        bValue = 10;
        aInstance = new A();
    }
    
    @Override
    public String toString() {
        return "";
    }
}

public class StackOverflowErrorToStringExample {
    public static void main(String[] args) {
        A obj = new A();
        System.out.println(obj.toString());
    }
}

當創(chuàng)建A對象的時候需要創(chuàng)建B對象,創(chuàng)建B對象的時候又要創(chuàng)建A對象,在兩個類之間形成了循環(huán)依賴,最終導致StackOverflowError。輸出結(jié)果:

Exception in thread "main" java.lang.StackOverflowError
    at main.java.B.(StackOverflowErrorToStringExample.java:24)
    at main.java.A.(StackOverflowErrorToStringExample.java:9)
    at main.java.B.(StackOverflowErrorToStringExample.java:24)
    at main.java.A.(StackOverflowErrorToStringExample.java:9)
    at main.java.B.(StackOverflowErrorToStringExample.java:24)
    at main.java.A.(StackOverflowErrorToStringExample.java:9)
    ...

如何處理StackOverflowError

  • 最簡單的方法就是細致的檢查stack trace,找出行號的重復模式。這些重復的行號代表了被遞歸調(diào)用的代碼。仔細審查代碼,理解為何遞歸不終止。
  • 如果你確認遞歸實現(xiàn)沒有問題,你可以通過-Xss參數(shù)增加棧的大小,這個參數(shù)可以在項目配置或命令行指定。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容