Почему максимальная глубина рекурсии, которую я могу достичь, недетерминирована?
я решил попробовать несколько экспериментов, чтобы узнать, что я могу узнать о размере кадров стека и как далеко через стек в настоящее время выполняется код. Есть два интересных вопроса, которые мы могли бы исследовать здесь:--11-->
- сколько уровней глубоко в стеке находится текущий код?
- сколько уровней рекурсии может достичь текущий метод, прежде чем он попадет в
StackOverflowError
?
глубина стека текущего выполнения код
4 ответов
наблюдаемое поведение зависит от оптимизатора HotSpot, однако это не единственная причина. Когда я запускаю следующий код
public static void main(String[] argv) {
System.out.println(System.getProperty("java.version"));
System.out.println(countDepth());
System.out.println(countDepth());
System.out.println(countDepth());
System.out.println(countDepth());
System.out.println(countDepth());
System.out.println(countDepth());
System.out.println(countDepth());
}
static int countDepth() {
try { return 1+countDepth(); }
catch(StackOverflowError err) { return 0; }
}
С JIT включен, я получаю такие результаты, как:
> f:\Software\jdk1.8.0_40beta02\bin\java -Xss68k -server -cp build\classes X
1.8.0_40-ea
2097
4195
4195
4195
12587
12587
12587
> f:\Software\jdk1.8.0_40beta02\bin\java -Xss68k -server -cp build\classes X
1.8.0_40-ea
2095
4193
4193
4193
12579
12579
12579
> f:\Software\jdk1.8.0_40beta02\bin\java -Xss68k -server -cp build\classes X
1.8.0_40-ea
2087
4177
4177
12529
12529
12529
12529
здесь эффект JIT хорошо виден, очевидно, оптимизированный код требует меньше пространства стека, и показано, что многоуровневая компиляция включена (действительно, используя -XX:-TieredCompilation
показывает один прыжок, если программа работает достаточно долго).
напротив, с отключенным JIT я получаю следующие результаты:
> f:\Software\jdk1.8.0_40beta02\bin\java -Xss68k -server -Xint -cp build\classes X
1.8.0_40-ea
2104
2104
2104
2104
2104
2104
2104
> f:\Software\jdk1.8.0_40beta02\bin\java -Xss68k -server -Xint -cp build\classes X
1.8.0_40-ea
2076
2076
2076
2076
2076
2076
2076
> f:\Software\jdk1.8.0_40beta02\bin\java -Xss68k -server -Xint -cp build\classes X
1.8.0_40-ea
2105
2105
2105
2105
2105
2105
2105
значения по-прежнему различаются, но не в пределах одного потока выполнения и с меньшей величиной.
таким образом, существует (довольно небольшая) разница, которая становится намного больше, если оптимизатор может уменьшить пространство стека, необходимое для вызова метода, например, из-за вставки.
что может вызвать такую разницу? Я не знаю, как это делает JVM, но один сценарий может заключаться в том, что способ применения ограничения стека требует определенное выравнивание стека конец адрес (например, соответствующие размеры страниц памяти) в то время как память распределение возвращает память с начальным адресом, который имеет более слабую гарантию выравнивания. Объедините такой сценарий с ASLR и всегда может быть разница, в пределах размера требования к выравниванию.
Why is the maximum recursion depth non-deterministic on Oracle's Java 8? And why is it deterministic on OpenJDK 7?
об этом, возможно, связано с изменениями в сборке мусора. Java может выбрать другой режим для gc каждый раз. http://vaskoz.wordpress.com/2013/08/23/java-8-garbage-collectors/
это устарело, но вы можете попробовать Thread.countStackFrames()
как
public static int levelsDeep() {
return Thread.currentThread().countStackFrames();
}
за Javadoc,
устаревший. определение этого вызова зависит от
suspend()
, который является устаревшим. Кроме того, результаты этого призыва никогда не были четко определены.подсчитывает количество кадров стека в этой теме. Нить должна быть подвешена.
Что касается того, почему вы наблюдаете недетерминированный поведение, я могу только предположить, что это какая-то комбинация JIT и сборщика мусора.
вам не нужно ловить исключение, просто создайте такой:
новый Throwable().getStackTrace()
или:
нить.currentThread().getStackTrace()
Он по-прежнему хакерский, поскольку результат специфичен для реализации JVM. И JVM может решить обрезать результат для лучшей производительности.