最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的StackOverflowError從原理到實戰(zhàn)指南(棧溢出的 4 種典型場景)

 更新時間:2026年03月07日 10:33:21   作者:會員源碼網(wǎng)  
java.lang.StackOverflowError 是 JVM 拋出的錯誤(Error) ,不是普通異常(Exception),本文給大家介紹Java中的StackOverflowError從原理到實戰(zhàn)指南(棧溢出的 4 種典型場景),感興趣的朋友跟隨小編一起看看吧

一、什么是 StackOverflowError?

java.lang.StackOverflowError 是 JVM 拋出的錯誤(Error) ,不是普通異常(Exception)。它表示:當(dāng)前線程的虛擬機棧空間被耗盡,無法再分配新的棧幀。

核心原理

  1. 每個線程有獨立的虛擬機棧,默認(rèn)大小約 1MB(可通過 -Xss 調(diào)整)。
  2. 每調(diào)用一個方法,JVM 會創(chuàng)建一個棧幀壓入棧中,存放局部變量、返回地址、操作數(shù)棧等。
  3. 方法執(zhí)行完畢,棧幀出棧。
  4. 當(dāng)壓棧速度遠大于出棧,??臻g被占滿,就拋出 StackOverflowError。

一句話總結(jié):方法調(diào)用層級太深,棧被撐爆了。

二、棧溢出的 4 種典型場景(附代碼)

1. 無限遞歸(最常見)

沒有正確的遞歸出口,方法無限調(diào)用自身。

public class StackOverflowDemo {
    public static void recursion() {
        recursion(); // 無終止條件
    }
    public static void main(String[] args) {
        recursion();
    }
}

報錯:直接拋出 StackOverflowError,堆棧信息瘋狂重復(fù)同一行。

2. 遞歸深度過大(有出口但太深)

public static int deepRecursion(int n) {
    if (n == 0) return 0;
    return deepRecursion(n - 1);
}
// 調(diào)用:deepRecursion(100000) → 棧溢出

默認(rèn)棧深度大約在 1000~2000 層,超過就會爆。

3. 方法循環(huán)調(diào)用(A→B→A→B…)

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

本質(zhì)和無限遞歸一樣,形成調(diào)用環(huán)。

4. 超大局部變量(少見但致命)

棧不僅存調(diào)用鏈,還存局部變量。一次性在棧上分配超大數(shù)組會直接爆棧。

public static void bigLocalVar() {
    int[] huge = new int[1024 * 1024]; // 棧上分配,直接溢出
}

注意:對象實例在堆,數(shù)組引用在棧,但超大基本類型數(shù)組會占滿棧空間。

三、關(guān)鍵知識點:Error vs Exception

  • Exception:可捕獲、可恢復(fù)(空指針、下標(biāo)越界等)。
  • Error:系統(tǒng)級錯誤,不建議捕獲,捕獲也無法恢復(fù)。
  • StackOverflowError 一旦發(fā)生,線程已無法正常執(zhí)行,catch 住也沒意義。

四、如何快速定位 StackOverflowError?

1. 看異常堆棧(最直接)

堆棧信息會大量重復(fù)某幾行,那就是遞歸 / 循環(huán)調(diào)用的根源。示例:

plaintext

Exception in thread "main" java.lang.StackOverflowError
at com.demo.StackOverflowDemo.recursion(StackOverflowDemo.java:5)
at com.demo.StackOverflowDemo.recursion(StackOverflowDemo.java:5)
at com.demo.StackOverflowDemo.recursion(StackOverflowDemo.java:5)
...

2. 用 jstack 抓線程棧

jstack -l <pid>

找到 RUNNABLE 且棧超長的線程,定位問題方法。

3. IDE 斷點調(diào)試

在可疑遞歸 / 循環(huán)處打斷點,觀察調(diào)用次數(shù)與條件是否正常收斂。

五、解決方案:從根本到臨時

1. 修復(fù)遞歸(首選)

  • 必須有明確終止條件
  • 每次遞歸必須向終止條件逼近
// 正確遞歸示例
public static int factorial(int n) {
    if (n <= 1) return 1; // 出口
    return n * factorial(n - 1); // 收斂
}

2. 遞歸改迭代 / 循環(huán)(根治深度問題)

用循環(huán) + 集合模擬棧,徹底擺脫棧深度限制。

// 迭代替代遞歸
public static int loopFactorial(int n) {
    int res = 1;
    for (int i = 2; i <= n; i++) res *= i;
    return res;
}

3. 增大??臻g(臨時方案)

通過 JVM 參數(shù) -Xss 調(diào)整線程棧大小:

-Xss256k
-Xss1m
-Xss2m

不建議濫用:棧過大會導(dǎo)致線程數(shù)減少,引發(fā) OOM,只能作為臨時兼容。

4. 解除循環(huán)調(diào)用

梳理依賴關(guān)系,避免 A↔B 無限調(diào)用。

5. 大對象移到堆

把棧上超大局部變量改成對象,分配到堆。

六、棧溢出 vs 堆溢出(OOM)

表格

對比項StackOverflowErrorOutOfMemoryError
發(fā)生區(qū)域虛擬機棧堆 / 方法區(qū) / 直接內(nèi)存
原因方法調(diào)用太深、棧幀太多堆內(nèi)存不足,無法分配對象
觸發(fā)場景遞歸、循環(huán)調(diào)用內(nèi)存泄漏、大對象、加載類過多
JVM 參數(shù)-Xss-Xms -Xmx

七、企業(yè)級避坑建議

  1. 慎用遞歸:能用迭代就不用遞歸。
  2. 遞歸必加出口與深度限制
  3. 禁止在棧上聲明超大數(shù)組。
  4. 框架使用注意:MyBatis 嵌套查詢、Spring AOP 嵌套切面、Lombok 構(gòu)造循環(huán)都可能隱式遞歸。
  5. 上線前壓測:極端數(shù)據(jù)(深度樹、超長鏈)必測。

八、總結(jié)

StackOverflowError 本質(zhì)就是棧空間被方法調(diào)用占滿。

  • 90% 是遞歸問題
  • 8% 是循環(huán)調(diào)用
  • 2% 是棧配置 / 局部變量問題

解決思路:先看堆棧定位重復(fù)代碼 → 修復(fù)遞歸 / 解除循環(huán) → 必要時調(diào)整 -Xss

只要掌握原理與排查流程,棧溢出就是最容易解決的錯誤之一。

到此這篇關(guān)于Java中的StackOverflowError從原理到實戰(zhàn)指南(棧溢出的 4 種典型場景)的文章就介紹到這了,更多相關(guān)Java StackOverflowError原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot手寫RestTemplate攔截器鏈,掌控HTTP請求實踐

    SpringBoot手寫RestTemplate攔截器鏈,掌控HTTP請求實踐

    本文介紹了在Spring項目中使用RestTemplate時遇到的問題及解決方案,通過自定義攔截器鏈來實現(xiàn)請求的統(tǒng)一處理,包括添加認(rèn)證Token、記錄請求日志、設(shè)置超時時間、實現(xiàn)失敗重試等,關(guān)鍵點在于攔截器鏈的順序和響應(yīng)流的處理,以及確保攔截器的線程安全
    2025-12-12
  • ReentrantLock 非公平鎖實現(xiàn)原理詳解

    ReentrantLock 非公平鎖實現(xiàn)原理詳解

    這篇文章主要為大家介紹了ReentrantLock 非公平鎖實現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 使用Spring Cloud Gateway實現(xiàn)動態(tài)路由的核心原理

    使用Spring Cloud Gateway實現(xiàn)動態(tài)路由的核心原理

    Spring Cloud Gateway 實現(xiàn)動態(tài)路由的核心是將路由規(guī)則從靜態(tài)配置遷移到外部數(shù)據(jù)源,并通過事件機制實時刷新路由緩存,本文介紹使用Spring Cloud Gateway實現(xiàn)動態(tài)路由的核心原理,感興趣的朋友跟隨小編一起看看吧
    2025-10-10
  • java去除集合中重復(fù)元素示例分享 java去除重復(fù)

    java去除集合中重復(fù)元素示例分享 java去除重復(fù)

    這篇文章主要介紹了java去除集合中重復(fù)元素示例,大家參考使用吧
    2014-01-01
  • MyBatis?Mapper?接口是如何找到并執(zhí)行SQL的

    MyBatis?Mapper?接口是如何找到并執(zhí)行SQL的

    本文將為你揭開MyBatis這層神秘的面紗,深入剖析其接口與SQL的映射原理,并總結(jié)在Spring?Boot環(huán)境下的最佳實踐和常見陷阱,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Java枚舉類接口實例原理解析

    Java枚舉類接口實例原理解析

    這篇文章主要介紹了Java枚舉類接口實例原理解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • Java聊天室之使用Socket實現(xiàn)傳遞對象

    Java聊天室之使用Socket實現(xiàn)傳遞對象

    這篇文章主要為大家詳細介紹了Java簡易聊天室之使用Socket實現(xiàn)傳遞對象功能,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以了解一下
    2022-10-10
  • mybatis plus in方法使用說明

    mybatis plus in方法使用說明

    這篇文章主要介紹了mybatis plus in方法使用說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Spring?Cloud?Gateway實現(xiàn)分布式限流和熔斷降級的示例代碼

    Spring?Cloud?Gateway實現(xiàn)分布式限流和熔斷降級的示例代碼

    這篇文章主要介紹了Spring?Cloud?Gateway實現(xiàn)分布式限流和熔斷降級的示例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-06-06
  • 微信開發(fā)協(xié)議小結(jié)

    微信開發(fā)協(xié)議小結(jié)

    通過本教程給大家分享微信開發(fā)協(xié)議小結(jié)的相關(guān)知識,非常不錯,具有一定的參考借鑒價值,感興趣的朋友一起看看吧
    2016-11-11

最新評論

来宾市| 抚顺市| 如东县| 安溪县| 射阳县| 华亭县| 纳雍县| 侯马市| 张家口市| 威信县| 嘉定区| 沈阳市| 清涧县| 北流市| 贵德县| 绩溪县| 土默特右旗| 长寿区| 旌德县| 怀宁县| 林芝县| 黄陵县| 湄潭县| 民乐县| 凤冈县| 万荣县| 遵义县| 永胜县| 淮南市| 富民县| 襄城县| 靖江市| 赣州市| 石首市| 九龙城区| 长海县| 剑川县| 紫金县| 临沭县| 手游| 聊城市|