首先,代码:
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 上,11.0.5+10 来自 AdoptOpenJDK。
$ 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?
我认为这是需要纠正的不正确行为。我已经提交了错误JDK-8236569。
事实证明,
-Xss
不是 4K 的倍数根本无法在 macOS 上运行。
-Xss
参数被处理两次。第一个(主)线程的堆栈大小由启动器配置。启动器简单地调用pthread_attr_setstacksize
而不预处理参数。
pthread_attr_setstacksize
的 Mac OS X 文档明确指出,如果 EINVAL
不是系统页面大小的倍数,则该函数返回 stacksize
。此行为与 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