我如何找到可用的堆栈空间的大小

How do i find out the size of available stack space?

本文关键字:堆栈 空间 何找      更新时间:2023-10-16

我们都知道堆栈正在向下增长,因此,这确实是一个简单的假设,即如果我们找到 last 声明的变量的地址,我们将拿出堆栈中最小的地址,因此我们可以假设此地址将是我们的剩余可用堆栈。

我做到了,我得到了笨拙的地址{0x000000dc9354f540} = {947364623680}我们知道堆栈向下增长,我们知道我们不能低于0。所以一点数学:

947364623680 / (1024*1024*1024) = 882.302060425

->他们是否暗示我的机器上有882GB的堆栈?

我对其进行了测试,显然在堆栈中分配了其他2MB后获得堆栈溢出例外:

uint8 array[1024*1024*2] = {};

,我的问题来了,这是我的实际堆栈大小吗?

,由于您的问题具有标签" visual-studio-debugging",我假设您使用Windows。

首先,您应该获得当前的堆栈指针。要么获取本地虚拟变量的地址(就像您现在一样(,要么通过RAW asm读取esp/rsp,要么获取本地虚拟变量的地址(就像您现在一样(,或通过win32 API呼叫GetThreadContext获得CPU寄存器(。

现在,为了找出可用的堆栈大小,您可以使用VirtualQuery查看此虚拟内存区域的起始地址(又称基础基础地址(。基本上减去这些指针会给您剩余的堆栈尺寸(精度至当前堆栈框架的大小(。

很久以前,我已经写了一篇有关此主题的文章,包括查询当前分配/保留的堆栈尺寸。如果需要,您可以在那里找到更多信息:

他们是否暗示我的机器上有882GB的堆栈?!

它与"机器上的堆栈"无关。这是关于虚拟地址空间,这与系统中可用的物理存储(RAM 页面文件(无关。

在Win32应用程序中的任何给定点留下的堆栈空间的近似值的另一种方法将是以下功能。它使用结构化的异常处理来捕获堆栈溢出异常。

注意: @Valdo的解决方案是正确的解决方案。我要发布此答案,因为这是解决问题的有趣方法。它将非常慢,因为它的运行时是线性的(根据堆栈尺寸(,而不是 @valdo的解决方案的恒定运行时。

static uint64_t GetAvailableStackSpace()
{
    volatile uint8_t var;
    volatile uint8_t* addr = &var;
    volatile uint8_t sink;
    auto filter = [](unsigned int code) -> int
    {
        return (code == EXCEPTION_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
    };
    __try
    {
        while (true)
        {
            addr = addr - 1024;
            sink = *addr;
        }
    }
    __except (filter(GetExceptionCode()))
    {
        return (&var - addr);
    }
    return 0;
}

这是@Valdo提到的VirtualQuery技术的实现。此功能返回可用的堆栈字节数量大约。我在Windows X64上进行了测试。

static uint64_t GetAvailableStackSpace()
{
    volatile uint8_t var;
    MEMORY_BASIC_INFORMATION mbi;
    auto virtualQuerySuccess = VirtualQuery((LPCVOID)&var, &mbi, sizeof(mbi));
    if (!virtualQuerySuccess)
    {
        return 0;
    }
    return &var - mbi.AllocationBase;
}