JVM速成手册

JVM相关内容
帅旋
关注
充电
IT宅站长,技术博主,共享单车手,全网id:arthinking。

Java最大栈深度有多大 | 堆栈,深度

发布于 2020-01-06 | 更新于 2024-03-03

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

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

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

1、测试案例

1.1、测试线程栈大小对栈深度的影响

下面我们用一个测试例子来说明:

有如下递归方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

输出内容:

1
2
3
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,输出内容:

1
2
3
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。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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:

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

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

1
2
3
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?

本文作者: 帅旋

本文链接: https://www.itzhai.com/columns/jvm/how-stack-frame-can-a-thread-hold.html

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

×
IT宅

关注公众号及时获取网站内容更新。