如何在计算Ackermann时检查堆栈使用情况

时间:2011-09-27 18:29:21

标签: c posix stack-overflow ackermann

我正在了解我的系统能够计算Ackermann算法的两个和三个参数版本。对于非常小的m和n值,我的系统将计算并打印从A0和A1方法调用返回的结果。然而,高于3或4的任何东西都不会返回并冻结我正在使用atm的终端。我的问题是我确定我的机器可以计算的m和n的值。

我已经尝试了一些事情来捕获堆栈溢出,因为我知道c ++没有stackoverflowexception我可以捕获。 try-catch块不起作用。在下面的代码中,我使用getrlimit()来查找堆栈限制,在主gStackRef中创建一个地址位置。我调用checkStack以递归方式检查指向gStackLimit的局部变量指针。

有没有更好的方法来检查与递归方法相关的堆栈使用情况?我也检查段故障?我会告诉你我在unix终端上运行。

#include <cstdlib>
#include <iostream>


#define _XOPEN_SOURCE_EXTENDED 1
#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlp);

using namespace std;

int * gStackRef;
int gStackLimit;

void checkStack(void);

int main(int argc, char *argv[])
{
        int temp = 0;
        gStackRef = &temp;
        rlimit myl;
        getrlimit(RLIMIT_STACK, &myl);
        gStackLimit = (myl.rlim_cur / 3 * 8 / 10) ;/* modified for segment fault */
        cout << gStackLimit << "\n";
        checkStack();
}

void checkStack()
{
        int temp = 0;
        int* pVariableHere = &temp;
        size_t stackUsage = gStackRef - pVariableHere;
        printf("Stack usage: %d / %d \n", stackUsage, gStackLimit);
        if(stackUsage > gStackLimit) return;
        else checkStack();
}

2 个答案:

答案 0 :(得分:2)

  

然而,任何高于3或4的东西都不会返回并冻结我正在使用atm的终端。

这就是Ackermann功能的重点。它发展得非常迅速。对于m >= 4n >= 3,如果您以递归方式计算A(m, n),我会怀疑您的函数会在您死亡之前返回。

  

我已经尝试了一些事情来捕获堆栈溢出,因为我知道c ++没有我可以捕获的stackoverflowexception。

当然不是。该过程超出了堆栈空间。它应该立即拆除。

  

有没有更好的方法来检查与递归方法相关的堆栈使用情况?

如果必须使用递归,请通过创建自己的堆栈数据结构来手动执行,该堆栈数据结构在堆上而不是在堆栈空间中分配。用它来跟踪你在递归中的位置。推送和弹出,然后递归,而不是通过嵌套方法调用递归。

但最后,你不应该使用递归来计算Ackermann。

答案 1 :(得分:0)

  

我已经尝试了一些事情来捕获堆栈溢出,因为我知道c ++没有stackoverflowexception我可以捕获。 try-catch块不起作用。在下面的代码中,我使用getrlimit()来查找堆栈限制,在主gStackRef中创建一个地址位置。我调用checkStack以递归方式检查指向gStackLimit的局部变量指针。

POSIX没有检测堆栈溢出的“安全”方法。堆栈溢出导致SIGSEGV信号,您(通常)不应该捕获这些信号,因为它们也表示一般的分段错误which should crash your program。 Windows环境可以使用EXCEPTION_STACK_OVERFLOW安全地处理堆栈溢出 - 但在这种情况下,Windows正在做的只是在堆栈末尾放置一个保护页面并通知SEH。如果你用完了保护页面(在忽略SEH例外之后),那么你的程序就会终止(就像在POSIX-land中一样)。

  

有没有更好的方法来检查与递归方法相关的堆栈使用情况?我也检查段故障?我会告诉你我在unix终端上运行。

没有。即使你正在做的事情也有不明确的行为。在某些机器上,堆栈会增长。在某些机器上,堆栈会逐渐减少。编译器可以在两个方法之间插入任意数量的slop空间。从技术上讲,编译器可以实现两个独立的堆栈,位于两个完全不同的内存段中,并且仍然符合要求。

如果要以堆栈安全方式计算Ackermann,请使用从堆分配的显式堆栈结构,或使用dynamic programming