【问题标题】:In the context of the CLR in .NET how is stack space allocated在 .NET 中的 CLR 上下文中,堆栈空间是如何分配的
【发布时间】:2011-08-23 21:31:27
【问题描述】:

在 .NET 中的 CLR 上下文中,堆栈空间是如何分配的,它通常受到什么限制?

例如:

任何给定的线程都可以继续添加到堆栈中直到内存用完吗?如果不; CLR 如何决定分配多少空间?它能否改变主意?

PS:只是为了说明一些上下文,这一切都始于关于如何构建一种计算斐波那契数列的方法的讨论,其中一个建议是递归函数。

【问题讨论】:

    标签: c# vb.net memory-management stack stack-overflow


    【解决方案1】:

    CLR 立即提交每个线程的完整堆栈空间,一旦它被创建。默认堆栈大小为 1MB。如果您将堆栈推送到该大小之上,则会发生堆栈溢出并引发错误。

    CLR 采用与本机代码不同的策略,本机代码仅保留 1MB,但按需提交。

    这些是实现细节。最好将堆栈简单地视为固定大小的数据结构。此视图适用于 .net 和本机堆栈实现。

    递归函数绝对是计算斐波那契最差的方法,因为它的复杂性是指数级的。相反,您应该使用时间线性且空间恒定的迭代算法。例如:

    static int fib(int n)
    {
        int result = 0;
        int a = 1;
        for (int i=1; i<=n; i++)
        {
            int temp = result;
            result = a;
            a = temp + a;
        }
        return result;
    }
    

    当然,实际上,您的结果变量早在您达到堆栈溢出之前就会溢出。但是对于 n 的值在 30-40 范围内,递归算法的性能是站不住脚的。

    另一种明智的方法是用预先计算的值填充静态数组。同样,由于值增长如此之快,您不需要一个非常大的数组来包含适合int 甚至long 的所有值。

    【讨论】:

    • @Marc Naive 递归算法,即fib(n)=fib(n-1)+fib(n-2) 具有指数复杂性,请参阅stackoverflow.com/questions/360748/… - 我同意我上面的陈述是草率的,我会纠正它
    • 啊,是的,因此我的“前两个术语” - 我想 即使在缓慢的一天我也不会想到将斐波那契实现那么糟糕 ;p
    • @Marc 如果你可以记忆,这是一个很好的实现。例如,我认为 Python 有一个内置的 memoize 装饰器,它可以将这个可怕的 fib 版本变成一个超级高效的版本。单个装饰器可以将 O(1^n) 变成 O(n)!
    • 好的工作比 1^n 便宜,然后;p(开玩笑,我知道你的意思)
    • @Marc 是的,我不太擅长这个 O() 东西!我想我应该写 O(k^n)。
    猜你喜欢
    • 2011-08-04
    • 2012-07-19
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    • 2023-03-27
    • 2017-03-25
    • 1970-01-01
    相关资源
    最近更新 更多