初始化数组时出现StackOverflow异常

时间:2019-06-25 12:08:47

标签: c# .net-core runtime-error runtime runtimeexception

我调用该方法并获取StackOverflowException。它不是递归调用,它仅包含数组初始化。我需要一个BigIntegers数组,即使int数组更大,代码也可以正常工作。我显示了简化的示例,在真实代码中,由于无法生成所需的数字,因此无法使用循环来填充数组,因此必须对所有数字进行硬编码。

设置: x64模式,.Net Core

error details中我们可以看到:

1)堆栈跟踪为空

2)错误可能起源于System.Collections.ListDictionaryInternal

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Before"); // <--- This is displayed

            var a = GetBigIntegers(); // <--- Mehtod is called

            Console.WriteLine("After"); // <--- We will never get there
        }


        static BigInteger[] GetBigIntegers()
        {
            // <--- Crash here
            return new BigInteger[]
            {
                1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
                // Many more lines (850-900) and they are 2-3 times longer than here
                1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
            };
        }
    }

我已经检查了IL代码,它看起来正确,大约需要40万行。

.method private hidebysig static 
    valuetype [System.Runtime.Numerics]System.Numerics.BigInteger[] GetBigIntegers () cil managed 
{
    // Method begins at RVA 0x207c
    // Code size 1130123 (0x113e8b)
    .maxstack 4
    .locals init (
        [0] valuetype [System.Runtime.Numerics]System.Numerics.BigInteger[]
    )

    // (no C# code)
    IL_0000: nop
    IL_0001: ldc.i4 66500
    IL_0006: newarr [System.Runtime.Numerics]System.Numerics.BigInteger
    IL_000b: dup
    IL_000c: ldc.i4.0
    //  return new BigInteger[66500]IL_000d: ldc.i4.1
    IL_000e: call valuetype [System.Runtime.Numerics]System.Numerics.BigInteger [System.Runtime.Numerics]System.Numerics.BigInteger::op_Implicit(int32)
    // (no C# code)
    IL_0013: stelem [System.Runtime.Numerics]System.Numerics.BigInteger
    IL_0018: dup
    IL_0019: ldc.i4.1
    IL_001a: ldc.i4.1
    IL_001b: call valuetype [System.Runtime.Numerics]System.Numerics.BigInteger [System.Runtime.Numerics]System.Numerics.BigInteger::op_Implicit(int32)
    IL_0020: stelem [System.Runtime.Numerics]System.Numerics.BigInteger
.....
    IL_113e75: dup
    IL_113e76: ldc.i4 66499
    IL_113e7b: ldc.i4.1
    IL_113e7c: call valuetype [System.Runtime.Numerics]System.Numerics.BigInteger [System.Runtime.Numerics]System.Numerics.BigInteger::op_Implicit(int32)
    IL_113e81: stelem [System.Runtime.Numerics]System.Numerics.BigInteger
    IL_113e86: stloc.0
    IL_113e87: br.s IL_113e89

    IL_113e89: ldloc.0
    IL_113e8a: ret
} // end of method Program::GetBigIntegers

我希望数组将被初始化并返回,但实际上我遇到了StackOverflow错误。

我知道我可以使用不同的方法来完成相同的工作,但是我想知道为什么不适用于这种方式。希望每个阅读此问题的人也对此感兴趣。

2 个答案:

答案 0 :(得分:1)

实际原因是评估堆栈框架的大小不足以容纳所放入的所有内容。

这样做的原因在于JIT编译器优化背后的原因,这些优化方法无法在大型方法中进行结构初始化(这会导致性能差的机器代码生成)。

Source

答案 1 :(得分:0)

.NET 将数组限制为成员的 2GB (或字节?)。因为它使用带符号的32位整数作为索引(最大索引为BaseEvent)。

可以使用不同的集合类型,这完全取决于您的需求,否则您可以使用更优雅的解决方案来修改方法。

最好的问候。