首先,代码:
public class StackSOF {
private int deep = 0;
public void stackLeak() {
deep++;
stackLeak();
}
public static void main(String[] args) {
StackSOF sof = new StackSOF();
try {
sof.stackLeak();
} catch (Throwable e) {
System.out.println(" stack deep = " + sof.deep + "\n\r" + e);
}
}
}
在macOS 10.15.2上,以及AdoptOpenJDK中的11.0.5 + 10。
$ java -Xint -Xss159k StackSOF
stack deep = 4422
java.lang.StackOverflowError
$ java -Xint -Xss160k StackSOF
stack deep = 668
java.lang.StackOverflowError
$ java -Xint -Xss161k StackSOF
stack deep = 4422
java.lang.StackOverflowError
为什么160k的最大堆栈深度小于159k?
答案 0 :(得分:2)
我认为这是不正确的行为,需要解决。我已经提交了错误JDK-8236569。
事实证明,-Xss
并非4K的倍数在macOS上根本不起作用。
-Xss
参数被处理两次。第一个(主)线程的堆栈大小由启动器配置。启动器simply calls pthread_attr_setstacksize
无需预处理参数。
但是,如果EINVAL
不是系统页面大小的倍数,则pthread_attr_setstacksize
的Mac OS X文档明确声明该函数返回stacksize
。此行为不同于Linux,Linux pthread_attr_setstacksize
可以接受奇数值。
-Xss
也由JVM处理,在这种情况下,值为页面大小的rounded:
// Make the stack size a multiple of the page size so that
// the yellow/red zones can be guarded.
JavaThread::set_stack_size_at_create(align_up(stack_size_in_bytes, vm_page_size()));
因此,新线程将具有正确调整的堆栈大小。如果您将测试代码更改为在新线程中运行,它将表现出预期的效果。
public class StackSOF {
private int deep = 0;
public void stackLeak() {
deep++;
stackLeak();
}
public static void main(String[] args) {
new Thread(() -> {
StackSOF sof = new StackSOF();
try {
sof.stackLeak();
} catch (Throwable e) {
System.out.println(" stack deep = " + sof.deep + "\n\r" + e);
}
}).start();
}
}
由于四舍五入关系,159k和160k之间没有区别:
$ java -Xint -Xss159k StackSOF
stack deep = 666
java.lang.StackOverflowError
$ java -Xint -Xss160k StackSOF
stack deep = 666
java.lang.StackOverflowError
$ java -Xint -Xss161k StackSOF
stack deep = 708
java.lang.StackOverflowError