Java最大棧深度有多大

無論你是跟同事、同學、上下級、同行、或者面試官討論技術問題的時候,很容易卷入JVM大型撕逼現(xiàn)場。為了能夠讓大家從大型撕逼現(xiàn)場中脫穎而出,最近我苦思冥想如何把知識點盡可能呈現(xiàn)的容易理解,方便記憶。于是就開啟了這一系列文章的編寫。為了讓JVM相關知識點能夠形成一個體系,arthinking將編寫整理一系列的專題,以盡量以圖片的方式描述相關知識點,并且最終把所有相關知識點串成了一張圖。持續(xù)更新中,歡迎大家閱讀。有任何錯落之處也請您高抬貴手幫忙指正,感謝!

Java運行時數(shù)據(jù)區(qū)域是如何工作的這篇文章我們知道,線程中的 棧結構如下:

image

每個棧幀包含:本地變量表,操作數(shù)棧,動態(tài)鏈接,返回地址等東西...

也就是說棧調(diào)用深度越大,棧幀就越多,就越耗內(nèi)存。

1、測試案例

1.1、測試線程棧大小對棧深度的影響

下面我們用一個測試例子來說明:

有如下遞歸方法:

public class StackTest {

    private int count = 0;

    public void recursiveCalls(String a){
        count++;
        System.out.println("stack depth: " + count);
        recursiveCalls(a);
    }

    public void test(){
        try {
            recursiveCalls("a");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        new StackTest().test();
    }

}

我們設置啟動參數(shù)

-Xms256m -Xmx256m -Xmn128m -Xss256k

輸出內(nèi)容:

stack depth: 1556
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)

可以發(fā)現(xiàn),棧深度為1556的時候,就報 StackOverflowError了。

接下來我們調(diào)整-Xss線程棧大小為 512k,輸出內(nèi)容:

stack depth: 3249
Exception in thread "main" java.lang.StackOverflowError
    at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)

發(fā)現(xiàn)棧深度變味了3249,說明了:

隨著線程棧的大小越大,能夠支持越多的方法調(diào)用,也即是能夠存儲更多的棧幀。

1.2、測試方法參數(shù)個對棧深度的影響

這里我們固定設置-Xss為256k。

我們知道此時的深度為:1556。

接下來我們給方法添加參數(shù):

public class StackTest {

    private int count = 0;

    public void recursiveCalls(String a){
        count++;
        System.out.println("stack depth: " + count);
        recursiveCalls(a);
    }

    public void test(){
        try {
            recursiveCalls("a");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        new StackTest().test();
    }

}

為何要添加參數(shù)呢,因為添加參數(shù)之后,棧幀中的本地變量表就會增加內(nèi)容,我們可以嘗試使用以下命令查看下Class文件的匯編指令:

javap -v StackTest.class

可以發(fā)現(xiàn)recursiveCalls方法的本地變量表的確增加了,對應方法的入?yún)?a:

      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      44     0  this   Lcom/itzhai/jvm/stacks/StackTest;
            0      44     1     a   Ljava/lang/String;

這個時候我們在執(zhí)行程序看看結果:

stack depth: 1318
Exception in thread "main" java.lang.StackOverflowError
    at java.nio.Buffer.<init>(Buffer.java:201)

可以發(fā)現(xiàn),棧深度由原來的1556編程了1318。

可以得出結論:

局部變量表內(nèi)容越多,那么棧幀就越大,棧深度就越小。

2、結論

  • 隨著線程棧的大小越大,能夠支持越多的方法調(diào)用,也即是能夠存儲更多的棧幀;
  • 局部變量表內(nèi)容越多,那么棧幀就越大,棧深度就越小。

我們在評審寫代碼的時候,發(fā)現(xiàn)了堆棧溢出,可以查看下對應類的本地變量表,是不是太多了,可不可以優(yōu)化下代碼,或者加大下線程棧的大小,以增加棧的深度。

知道了這個,我們下次面試別人的時候也可以問問對方看看了,嘿嘿。

References

What is the maximum depth of the java call stack?


本文為arthinking基于相關技術資料和官方文檔撰寫而成,確保內(nèi)容的準確性,如果你發(fā)現(xiàn)了有何錯漏之處,煩請高抬貴手幫忙指正,萬分感激。

大家可以關注我的博客:itzhai.com 獲取更多文章,我將持續(xù)更新后端相關技術,涉及JVM、Java基礎、架構設計、網(wǎng)絡編程、數(shù)據(jù)結構、數(shù)據(jù)庫、算法、并發(fā)編程、分布式系統(tǒng)等相關內(nèi)容。

如果您覺得讀完本文有所收獲的話,可以關注我的賬號,或者點贊的,您的支持就是我寫作的動力!關注我的公眾號,及時獲取最新的文章。


本文作者: arthinking

博客鏈接: https://www.itzhai.com/jvm/how-stack-frame-can-a-thread-hold.html

Java最大棧深度有多大

版權聲明: BY-NC-SA許可協(xié)議:創(chuàng)作不易,如需轉載,請務必附加上博客鏈接,謝謝!


image
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

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