【发布时间】:2015-03-04 21:17:03
【问题描述】:
我在 C# 中有这两段代码:
首先
class Program
{
static Stack<int> S = new Stack<int>();
static int Foo(int n) {
if (n == 0)
return 0;
S.Push(0);
S.Push(1);
...
S.Push(999);
return Foo( n-1 );
}
}
第二
class Program
{
static Stack S = new Stack();
static int Foo(int n) {
if (n == 0)
return 0;
S.Push(0);
S.Push(1);
...
S.Push(999);
return Foo( n-1 );
}
}
他们都做同样的事情:
创建一个堆栈(第一个示例在
<int>中通用,第二个示例使用一个对象堆栈)。声明一个递归调用自身 n 次 (n >= 0) 并在每一步中将 1000 个整数压入创建的堆栈的方法。
当我使用Foo(30000) 运行第一个示例时,没有发生异常,但是第二个示例使用Foo(1000) 崩溃,只有 n = 1000。
当我看到为这两种情况生成的CIL 时,唯一的区别是每次推送的拳击部分:
首先
IL_0030: ldsfld class [System]System.Collections.Generic.Stack`1<int32> Test.Program::S
IL_0035: ldc.i4 0x3e7
IL_003a: callvirt instance void class [System]System.Collections.Generic.Stack`1<int32>::Push(!0)
IL_003f: nop
第二
IL_003a: ldsfld class [mscorlib]System.Collections.Stack Test.Program::S
IL_003f: ldc.i4 0x3e7
IL_0044: box [mscorlib]System.Int32
IL_0049: callvirt instance void [mscorlib]System.Collections.Stack::Push(object)
IL_004e: nop
我的问题是:如果第二个示例的 CIL 堆栈没有显着过载,为什么它会比第一个示例“更快”崩溃?
【问题讨论】:
-
我刚刚运行了代码,在调试模式下都在 30k 时崩溃,在发布模式下都在 30k 时运行良好。您可能只在调试模式下运行了非通用版本。
-
@JamesThorpe 这些调用不会影响堆栈帧的大小,因为它们在递归时不会在堆栈上。
-
您在两个示例中创建的堆栈结构与线程堆栈无关,因为它们位于堆中。因此,调用 Stack.Push 方法一次或一百万次并不重要:它不会影响线程堆栈的使用
-
我在编译到 x86 时复制了 OP 的问题。
Stack在 n = 19261 处崩溃;Stack<int>在 n = 3 时崩溃(即很久以后)。 -
@LeandroCastilloValdés 您是否遇到溢出异常、内存不足异常或其他问题?
标签: c# stack-overflow il