并行递归过程中发生StackOverflow错误



我使用并行递归来计算一个数字是奇数还是偶数。我使用了长类型,但当输入数字(x(有5位数或更多时,我会遇到StackOverflowError。我不明白为什么。

static boolean Odd(long n) {
if (n == 0) return false;
else return Even(n - 1);     
}
static boolean Even(long d) {
if (d == 0) return true;
else return Odd(d - 1);  
}
public static void main(String[] args) {
long x = 0; 
while(x>=0) {
System.out.println("Insert number");
x = SavitchIn.readLong();
boolean isOdd = Odd(x);
if(isOdd) {
System.out.println("Odd number");
}else {
System.out.println("Even number");
}
}
}

要了解为什么会出现StackOverflowError,您需要了解在代码中进行函数调用时会发生什么,以及在实际处理器中是如何执行的。

运行程序时,所有相关的代码和符号都会加载到内存中,然后一行接一行地执行。您有一个名为Program Counter的寄存器,它基本上充当指向当前执行代码行的指针。

然而,当要执行的行是一个函数时,该函数的代码不能立即在下一个存储器地址上可用。相反,此功能将在内存中的不同位置可用。因此,当处理单元看到函数调用时,它会复制几个重要的统计数据,如程序计数器[PC](了解代码执行了多远(、寄存器值等,并将这些数据推入堆栈。这个数据结构是堆栈的原因可以用以下简单的代码示例来解释:

public class Example {
public int func1() {
int a = 10, b = 20;
int c = a+b;
return c;
}

public int func2() {
int a = 100;
int b = func1();
return a*b;
}
public static void main(String args[]) {
int attr = 10;
int result = func2() / 10;
System.out.println(result);
}
}

在本例中,正如您所知,代码执行从``main``函数开始。因此,执行主函数的第1行,并将attr变量设置为10。然后它转到第2行,在这里,它看到有一个函数调用,即func2。

因此,此时,系统会将PC和其他内存推入堆栈,然后移动到func2的位置。在func2中,执行第1行,将a的值设置为100。func2的第2行再次是一个函数调用,因此所有数据现在再次被推送到上一次推送的堆栈上,func1被执行。

在func1中,我们没有函数调用,因此不会发生更多的堆栈推送。Func1有三行代码,它们一行接一行地执行。然而,仅仅因为我们到达了func1的末尾,并不意味着我们已经完成了代码的执行。我们仍然需要执行func2和main的其余部分。我们需要执行的第一组代码是func2,因为func2调用了func1。这正是我们在堆栈中所拥有的(堆栈顶部有func2值(。因此,我们弹出它,继续执行func2,完成后,我们返回堆栈,看到主函数中有一个条目。所以我们把它弹出并完成执行。

现在我们已经有了一些了解,在您的代码中,您可以看到Odd((和Even((方法递归地相互调用。对于一小部分5,我们可以看到以下情况:

Main( 
-push-> Odd(5 
-push-> Even(4 
-push-> Odd(3 
-push-> Even(2 
-push-> Odd(1 
-push-> Even(0 
[return's true]
) -pop-> 
) -pop->
) -pop->
) -pop-> 
) -pop-> 
) -pop-> 
)

因此,在这种情况下,对于像5这样的小数字,我们可以看到堆栈的大小高达6。现在,对于像99999这样的5位数字,堆栈的最大大小将是100000,这对堆栈来说是一个非常大的数字。请记住,对于每个堆栈条目,我们都会复制堆栈上的PC、寄存器等。

这就是为什么您会看到5位数的StackOverflowError。当位数为5时,堆栈的大小会变得非常大,这可能超出了运行代码的处理器的能力。

最新更新