简体   繁体   English

C#编译器(csc.exe)内存溢出编译嵌套类型和Linq

[英]C# compiler (csc.exe) memory overflow compiling nested types and Linq

I found one unpleasant behavior developing with Visual Studio. 我发现使用Visual Studio开发了一个不愉快的行为。 It was hanging my machine while compiling C#. 在编译C#时它挂起了我的机器。

I have reduced behavior to the next minimal source code 我已经减少了对下一个最小源代码的行为

using System.Collections.Generic;
using System.Linq;

namespace memoryOverflowCsharpCompiler {

    class SomeType { public decimal x; }

    class TypeWrapper : Dictionary<int,
                        Dictionary<int,
                        Dictionary<int, SomeType [] []>>> {

        public decimal minimumX() {
            return base.Values.Min(a =>
                      a.Values.Min(b =>
                      b.Values.Min(c =>
                      c       .Sum(d =>
                      d       .Sum(e => e.x)))));
        }
    }
}

Compiling with 用。编译

PROMPT> csc source.cs

    *** BANG! overflow memory usage (up to ~3G)

PROMPT> csc /?
Microsoft (R) Visual C# Compiler version 12.0.30501.0
Copyright (C) Microsoft Corporation. All rights reserved.
...

(using Windows 8.1 Pro N x64; csc compiler process is running with 32bits) (使用Windows 8.1 Pro N x64; csc编译器进程运行32位)

sightly modifications don't produce this behavior (eg. changing decimal by int , reducing one nested level, ...), performing a big Select then reducing, works fine 明显的修改不会产生这种行为(例如,通过int更改decimal ,减少一个嵌套级别,...),执行大Select然后减少,工作正常

Explicit workaround: 明确的解决方法:

            return base.Values.SelectMany(a =>
                      a.Values.SelectMany(b =>
                      b.Values.Select    (c =>
                      c.       Sum       (d =>
                      d.       Sum       (e => e.x))))).Min();

Although this explicit workaround exists, it not guaranteed that this behavior will not occur again. 虽然存在此显式解决方法,但不保证不会再次发生此行为。

What's wrong? 怎么了?

Thank you! 谢谢!

It seems that generic type resolution fails in that case. 在这种情况下,通用类型解析似乎失败了。 Changing from decimal to int works by chance. decimalint是偶然的。 If you increase nesting level, than you'll see that it also fails for int. 如果你增加嵌套级别,你会发现它也失败了。 On my x64 machine this code compiles for both int and decimal and uses around 2.5GB of memory, but increasing nesting level results in overflow when memory usage growing to aroung 4GB. 在我的x64机器上,这个代码编译intdecimal并使用大约2.5GB的内存,但是当内存使用量增加到4GB时,增加嵌套级别会导致溢出。

Specifying type argument explicitly allows to compile code: 明确指定类型参数允许编译代码:

class TypeWrapper : Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, SomeType[][]>>>>
{
    public decimal minimumX()
    {
        return base.Values
            .Min<Dictionary<int, Dictionary<int, Dictionary<int, SomeType[][]>>>, decimal>(a => a.Values
                .Min<Dictionary<int, Dictionary<int, SomeType[][]>>, decimal>(b => b.Values
                    .Min<Dictionary<int, SomeType[][]>, decimal>(c => c.Values
                        .Min(d => d
                            .Sum(e => e.Sum(f => f.x))
                        )
                    )
                )
            );
    }
}

Also compiler works when you reduce nesting by introducing local variable: 当您通过引入局部变量来减少嵌套时,编译器也可以工作:

class TypeWrapper : Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, SomeType[][]>>>>
{
    public decimal minimumX()
    {
        Func<Dictionary<int, SomeType[][]>, decimal> inner = (Dictionary<int, SomeType[][]> c) => c.Values
                        .Min(d => d
                            .Sum(e => e.Sum(f => f.x))
                        );

        return base.Values
            .Min(a => a.Values
                .Min(b => b.Values
                    .Min(inner)
                )
            );
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM