一、问题:Java最大支持栈深度有多大?
1.分析
由JVM的内存结构我们可知:
- 随着线程栈的大小越大,能够支持越多的方法调用,也即是能够存储更多的栈帧;
- 局部变量表内容越多,那么栈帧就越大,栈深度就越小。
2.详解
从Java运行时数据区域我们知道,线程中的虚拟机栈结构如下:
每个栈帧包含:本地变量表,操作数栈,动态链接,返回地址等东西。也就是说栈调用深度越大,栈帧就越多,就越耗内存。
3、测试案例
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();
}
}
为何要添加参数呢,因为添加参数之后&