Для проверки того, как глубокая рекурсия в Scala может проникать глубоко на мою машину, была написана следующая программа. Я предполагаю, что в основном это зависит от размера стека, назначенного этой программе. Однако, после вычисления максимальной глубины рекурсии (исключения catching, когда она появляется) и попытки имитировать рекурсию этой глубины, я получил нечетные выходы.Разница глубины рекурсии Scala и StackOverflowError ниже допустимой глубины
object RecursionTest {
def sumArrayRec(elems: Array[Int]) = {
def goFrom(i: Int, size: Int, elms: Array[Int]): Int = {
if (i < size) elms(i) + goFrom(i + 1, size, elms)
else 0
}
goFrom(0, elems.length, elems)
}
def main(args: Array[String]) {
val recDepth = recurseTest(0, 0, Array(1))
println("sumArrayRec = " + sumArrayRec((0 until recDepth).toArray))
}
def recurseTest(i: Int, j: Int, arr: Array[Int]): Int = {
try {
recurseTest(i + 1, j + 1, arr)
} catch { case e: java.lang.StackOverflowError =>
println("Recursion depth on this system is " + i + ".")
i
}
}
}
Результаты варьируются в зависимости от исполнения программы.
Одним из них является желательным выход:
/usr/lib/jvm/java-8-oracle/bin/java
Recursion depth on this system is 7166.
sumArrayRec = 25672195
Process finished with exit code 0
Тем не менее, второй возможный выход, который я получаю указывает на ошибку:
/usr/lib/jvm/java-8-oracle/bin/java
Recursion depth on this system is 8129.
Exception in thread "main" java.lang.StackOverflowError
at RecursionTest$.goFrom$1(lab44.scala:6)
at RecursionTest$.goFrom$1(lab44.scala:6)
at RecursionTest$.goFrom$1(lab44.scala:6)
(...)
at RecursionTest$.goFrom$1(lab44.scala:6)
at RecursionTest$.goFrom$1(lab44.scala:6)
Process finished with exit code 1
я не наблюдал никакой зависимости или отношения их , Я только что получил первый, а второй раз
Все это привело меня к следующим вопросам:
- Зачем возникает ошибка и что вызывает ее?
- Это ошибка переполнения стека, и если да ...
- Почему размер стека изменяется в то же время, когда программа работает? Возможно ли это?
Когда я изменил println("sumArrayRec = " + sumArrayRec((0 until recDepth).toArray))
в println("sumArrayRec = " + sumArrayRec((0 until recDepth - 5000).toArray))
, так гораздо меньше, поведение остается тем же самым.
Почему вы сказали, что recurseTest нажимает только два параметра, так как он получает три параметра? –
, поэтому он создает 2 новых ints, 2 ints отправляются на него и один указатель, поэтому у вас есть около 5 ints в стеке, исключая инструкции, поэтому массив может быть оптимизирован, так как он не используется.На самом деле вы не можете сказать, если не посмотрите на сгенерированную сборку, -XX: + UnlockDiagnosticVMOptions -XX: + PrintAssembly', но оптимизация JVM может изменить их во время выполнения – Noah