在 .NET 中的 CLR 上下文中,堆栈空间是如何分配的

Posted

技术标签:

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

,它通常受到什么限制?

例如:

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

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

【问题讨论】:

【参考方案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) 具有指数复杂性,请参阅***.com/questions/360748/… - 我同意我上面的陈述是草率的,我会纠正它 啊,是的,因此我的“前两个术语” - 我想 即使在缓慢的一天我也不会想到将斐波那契实现那么糟糕 ;p @Marc 如果你可以记忆,这是一个很好的实现。例如,我认为 Python 有一个内置的 memoize 装饰器,它可以将这个可怕的 fib 版本变成一个超级高效的版本。单个装饰器可以将 O(1^n) 变成 O(n)! 好的工作比 1^n 便宜,然后;p(开玩笑,我知道你的意思) @Marc 是的,我不太擅长这个 O() 东西!我想我应该写 O(k^n)。

以上是关于在 .NET 中的 CLR 上下文中,堆栈空间是如何分配的的主要内容,如果未能解决你的问题,请参考以下文章

VB.NET 表单变量是如何处理的

.NET - 存储在地址空间中的堆或堆栈上的函数变量?

clr的原因! PerfView CPU 堆栈中的 JIT_New

最大线程堆栈大小.NET?

WPF使用其它的命名空间(宝典1)

SQL CLR 函数返回错误尝试使用上下文创建表和插入行