StackOverflowError 表示線程棧幀深度超過 JVM 限制。本文實驗三種常見觸發方式:遞歸調用無終止條件、大量線程併發、棧大小設定過小,並解析為何「大量區域變數」無法撐爆棧(Java 物件在堆、基本型區域變數在棧但編譯器優化、棧可動態擴展)。
public class StackOverflowDemo {
private static void recursive() {
recursive(); // 無終止條件
}
public static void main(String[] args) {
recursive(); // 幾千次調用後拋出 StackOverflowError
}
}
排查:堆疊追蹤顯示大量重複行號,定位遞歸方法,補充終止條件或改寫為迴圈。
// VM 參數:-Xss128k(預設通常 1024k)
public class SmallStackDemo {
static void deep(int n) {
if (n == 0) return;
deep(n - 1);
}
public static void main(String[] args) {
deep(5000); // 小棧下更快溢位
}
}
建議:生產環境避免設極小 -Xss,預設 1MB 足夠絕多數業務;若業務確有深度遞歸,優先改迴圈。
public class ThreadStackDemo {
public static void main(String[] args) {
while (true) {
new Thread(() -> {
while (true) { /* 空跑佔用棧 */ }
}).start();
}
}
}
實測現象:記憶體增長至系統上限(如 7.9GB)後停滯,未拋出 OutOfMemoryError: unable to create native thread,原因可能為 OS 線程數限制(ulimit -u)或 JVM 內部保護機制。
long a0=0; long a1=0; ... 這樣寫會被 JIT 優化為常數或直接捨棄(未使用)。| 工具/參數 | 用途 |
|---|---|
-Xss | 設定單線程棧大小,如 -Xss512k |
jstack <pid> | 列印線程堆疊,定位遞歸深度 |
-XX:+PrintStackTraces | JVM 崩潰時列印所有線程堆疊 |
| VisualVM / JConsole | 監控線程數、棧使用情況 |
Deque)實現迴圈。-Xss,僅在單元測試驗證深度遞歸時調小複現問題。ThreadPoolExecutor),避免無限創建線程耗盡系統資源。