StackOverFlowError(棧溢位)

快些兒發表於2020-09-30

原因

函式呼叫棧太深了,注意程式碼中是否有了迴圈呼叫方法而無法退出的情況

原理

每一個 JVM 執行緒都擁有一個私有的 JVM 執行緒棧,用於存放當前執行緒的 JVM 棧幀(包括被呼叫函式的引數、區域性變數和返回地址等)。如果某個執行緒的執行緒棧空間被耗盡,沒有足夠資源分配給新建立的棧幀,就會丟擲 java.lang.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;
      }
}

當 main() 方法被呼叫後,執行執行緒按照程式碼執行順序,將它正在執行的方法、基本資料型別、物件指標和返回值包裝在棧幀中,逐一壓入其私有的呼叫棧,整體執行過程如下圖所示:

首先,程式啟動後,main() 方法入棧。

然後,a() 方法入棧,變數 x 被宣告為 int 型別,初始化賦值為 0。注意,無論是 x 還是 0 都被包含在棧幀中。

接著,b() 方法入棧,建立了一個 Car 物件,並被賦給變數 y。請注意,實際的 Car 物件是在 Java 堆記憶體中建立的,而不是執行緒棧中,只有 Car 物件的引用以及變數 y 被包含在棧幀裡。

最後,c() 方法入棧,變數 z 被宣告為 float 型別,初始化賦值為 0f。同理,z 還是 0f 都被包含在棧幀裡。

當方法執行完成後,所有的執行緒棧幀將按照後進先出的順序逐一出棧,直至棧空為止。

StackOverFlowError 是如何產生的(原因)?

如上所述,JVM 執行緒棧儲存了方法的執行過程、基本資料型別、區域性變數、物件指標和返回值等資訊,這些都需要消耗記憶體。一旦執行緒棧的大小增長超過了允許的記憶體限制,就會丟擲 java.lang.StackOverflowError 錯誤。

引發 StackOverFlowError 的常見原因有以下幾種:

  1. 無限遞迴迴圈呼叫(最常見)。

  2. 執行了大量方法,導致執行緒棧空間耗盡。

  3. 方法內宣告瞭海量的區域性變數。

  4. native 程式碼有棧上分配的邏輯,並且要求的記憶體還不小,比如 java.net.SocketInputStream.read0 會在棧上要求分配一個 64KB 的快取(64位 Linux)。

下面這段程式碼通過無限遞迴呼叫最終引發了 java.lang.StackOverflowError 錯誤。

public class StackOverflowErrorExample {      

	public static void main(String args[]) {
            a();
      }      
      public static void a() {
            a();
      }
}

在這種情況下,a() 方法將無限入棧,直至棧溢位,耗盡執行緒棧空間,如下圖所示。

Exception in thread "main" java.lang.StackOverflowError
    at StackOverflowErrorExample.a(StackOverflowErrorExample.java:10)

常見的解決方法

  1. 修復引發無限遞迴呼叫的異常程式碼, 通過程式丟擲的異常堆疊,找出不斷重複的程式碼行,按圖索驥,修復無限遞迴 Bug。

  2. 排查是否存在類之間的迴圈依賴。

  3. 排查是否存在在一個類中對當前類進行例項化,並作為該類的例項變數。

  4. 通過 JVM 啟動引數 -Xss 增加執行緒棧記憶體空間, 某些正常使用場景需要執行大量方法或包含大量區域性變數,這時可以適當地提高執行緒棧空間限制,例如通過配置 -Xss2m 將執行緒棧空間調整為 2 mb。

部分知識引用自:
https://www.imooc.com/article/details/id/291031

相關文章