无论你是跟同事、同学、上下级、同行、或者面试官讨论技术问题的时候,很容易卷入JVM大型撕逼现场。为了能够让大家从大型撕逼现场中脱颖而出,最近我苦思冥想如何把知识点尽可能呈现的容易理解,方便记忆。于是就开启了这一系列文章的编写。为了让JVM相关知识点能够形成一个体系,arthinking将编写整理一系列的专题,以尽量以图片的方式描述相关知识点,并且最终把所有相关知识点串成了一张图。持续更新中,欢迎大家阅读。有任何错落之处也请您高抬贵手帮忙指正,感谢!
从Java运行时数据区域是如何工作的这篇文章我们知道,线程中的 栈结构如下:
image每个栈帧包含:本地变量表,操作数栈,动态链接,返回地址等东西...
也就是说栈调用深度越大,栈帧就越多,就越耗内存。
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
版权声明:
BY-NC-SA
许可协议:创作不易,如需转载,请务必附加上博客链接,谢谢!
image
网友评论