Java最大栈深度有多大

Java运行时数据区域是如何工作的这篇文章我们知道,线程中的 栈结构如下:

每个栈帧包含:本地变量表,操作数栈,动态链接,返回地址等东西…

也就是说栈调用深度越大,栈帧就越多,就越耗内存。

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();
    }

}

我们设置启动参数

-Xms256m -Xmx256m -Xmn128m -Xss256k

输出内容:

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

可以发现,栈深度为1556的时候,就报 StackOverflowError了。

接下来我们调整-Xss线程栈大小为 512k,输出内容:

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

发现栈深度变味了3249,说明了:

随着线程栈的大小越大,能够支持越多的方法调用,也即是能够存储更多的栈帧。

1.2、测试方法参数个对栈深度的影响

这里我们固定设置-Xss为256k。

我们知道此时的深度为:1556。

接下来我们给方法添加参数:

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();
    }

}

为何要添加参数呢,因为添加参数之后,栈帧中的本地变量表就会增加内容,我们可以尝试使用以下命令查看下Class文件的汇编指令:

javap -v StackTest.class

可以发现recursiveCalls方法的本地变量表的确增加了,对应方法的入参 a:

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

这个时候我们在执行程序看看结果:

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

可以发现,栈深度由原来的1556编程了1318。

可以得出结论:

局部变量表内容越多,那么栈帧就越大,栈深度就越小。

2、结论

  • 随着线程栈的大小越大,能够支持越多的方法调用,也即是能够存储更多的栈帧;
  • 局部变量表内容越多,那么栈帧就越大,栈深度就越小。

我们在评审写代码的时候,发现了堆栈溢出,可以查看下对应类的本地变量表,是不是太多了,可不可以优化下代码,或者加大下线程栈的大小,以增加栈的深度。

知道了这个,我们下次面试别人的时候也可以问问对方看看了,嘿嘿。

References

What is the maximum depth of the java call stack?


本文为arthinking基于相关技术资料和官方文档撰写而成,确保内容的准确性,如果你发现了有何错漏之处,烦请高抬贵手帮忙指正,万分感激。

大家可以关注我的博客:itzhai.com 获取更多文章,我将持续更新后端相关技术,涉及JVM、Java基础、架构设计、网络编程、数据结构、数据库、算法、并发编程、分布式系统等相关内容。

如果您觉得读完本文有所收获的话,可以关注我的账号,或者点赞的,您的支持就是我写作的动力!关注我的公众号,及时获取最新的文章。


本文作者: arthinking

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

Java最大栈深度有多大

版权声明: 版权归作者所有,未经许可不得转载,侵权必究!联系作者请加公众号。


  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是Java中求二叉树深度的两种方法: 方法一:递归法 在递归方法中,我们首先检查根节点是否为空。如果为空,说明二叉树为空树,深度为0。然后,我们使用递归的方式分别计算左子树和右子树的最大深度。最后,我们返回左子树和右子树中深度较大的值加1,即为二叉树的最大深度。 ```java public class Solution { public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } //递归版本 public int TreeDepth(TreeNode root) { if(root==null) return 0; int nLeft=TreeDepth(root.left); int nRight=TreeDepth(root.right); return (nLeft>nRight)?(nLeft+1):(nRight+1); } } ``` 方法二:非递归法 在非递归方法中,我们使用一个来存储每个节点以及它们的深度。我们首先将根节点和深度0入。然后,我们不断从中取出节点,如果该节点有左子树或右子树,则将它们和对应的深度。我们不断重复这个过程,直到为空。最后,我们返回最大深度。 ```java import java.util.Stack; public class Solution { public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } //非递归版本 public int TreeDepth(TreeNode root) { if(root==null) return 0; Stack<TreeNode> stack=new Stack<>(); Stack<Integer> depth=new Stack<>(); stack.push(root); depth.push(1); int maxDepth=0; while(!stack.isEmpty()){ TreeNode node=stack.pop(); int d=depth.pop(); maxDepth=Math.max(maxDepth,d); if(node.left!=null){ stack.push(node.left); depth.push(d+1); } if(node.right!=null){ stack.push(node.right); depth.push(d+1); } } return maxDepth; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值