StackOverFlowError(棧溢位)
原因
函式呼叫棧太深了,注意程式碼中是否有了迴圈呼叫方法而無法退出的情況
原理
每一個 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 的常見原因有以下幾種:
-
無限遞迴迴圈呼叫(最常見)。
-
執行了大量方法,導致執行緒棧空間耗盡。
-
方法內宣告瞭海量的區域性變數。
-
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)
常見的解決方法
-
修復引發無限遞迴呼叫的異常程式碼, 通過程式丟擲的異常堆疊,找出不斷重複的程式碼行,按圖索驥,修復無限遞迴 Bug。
-
排查是否存在類之間的迴圈依賴。
-
排查是否存在在一個類中對當前類進行例項化,並作為該類的例項變數。
-
通過 JVM 啟動引數 -Xss 增加執行緒棧記憶體空間, 某些正常使用場景需要執行大量方法或包含大量區域性變數,這時可以適當地提高執行緒棧空間限制,例如通過配置 -Xss2m 將執行緒棧空間調整為 2 mb。
部分知識引用自:
https://www.imooc.com/article/details/id/291031
相關文章
- StackOverflowError堆疊溢位錯誤Error
- 棧溢位基礎
- 阿里大佬講解Java記憶體溢位示例(堆溢位、棧溢位)阿里Java記憶體溢位
- 手動寫java記憶體溢位 java.lang.StackOverflowErrorJava記憶體溢位Error
- 64位Linux下的棧溢位Linux
- 棧溢位基礎及利用
- YoungzsoftCMailServer遠端棧溢位漏洞AIServer
- Java棧溢位|記憶體洩漏|記憶體溢位Java記憶體溢位
- 記憶體和棧溢位問題定位記憶體
- 使用metasploit進行棧溢位攻擊-5
- 從CVE復現看棧溢位漏洞利用
- [二進位制漏洞]棧(Stack)溢位漏洞 Linux篇Linux
- pwntools緩衝區溢位與棧沒對齊
- Python中的棧溢位及解決辦法Python
- Linux pwn入門教程(1)——棧溢位基礎Linux
- Kernel Stack棧溢位攻擊及保護繞過
- 記憶體溢位:native溢位 和 上層溢位記憶體溢位
- 記一次linux x64 的棧溢位Linux
- Re:從零開始的pwn學習(棧溢位篇)
- 記一次棧溢位異常問題的排查
- 尾遞迴 - 杜絕記憶體洩漏溢位爆棧遞迴記憶體
- MPU:鴻蒙輕核心的任務棧的溢位檢察官鴻蒙
- 深入淺出CPU眼中的函式呼叫&棧溢位攻擊函式
- DLink 815路由器棧溢位漏洞分析與復現路由器
- 整數溢位
- Python經典棧緩衝區溢位獲取root許可權Python
- PWN(棧溢位漏洞)-原創小白超詳細[Jarvis-level0]JAR
- CVE-2010-3333-office RTF棧溢位漏洞分析
- 記憶體溢位記憶體溢位
- 溢位OF和進位CF區別
- css 盒子溢位問題CSS
- Java記憶體溢位Java記憶體溢位
- JBOSS記憶體溢位記憶體溢位
- 堆溢位學習筆記筆記
- 聊聊資料溢位的事
- CSS 元素溢位是什麼?CSS
- 堆溢位之OverlappingAPP
- CSS(溢位_判斷IE版本)CSS