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

标签 c# linq visual-studio csc

我发现了一种使用 Visual Studio 开发的令人不快的行为。它在编译 C# 时挂了我的机器。

我已将行为减少到下一个最小源代码

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)))));
        }
    }
}

编译

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.
...

(使用 Windows 8.1 Pro N x64;csc 编译器进程以 32 位运行)

轻微修改不会产生此行为(例如,将 decimal 更改为 int,减少一个嵌套级别,...),执行大的 Select 然后减少,工作正常

明确的解决方法:

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

虽然存在这种明确的解决方法,但不能保证这种行为不会再次发生。

怎么了?

谢谢!

最佳答案

在那种情况下,泛型类型解析似乎失败了。从 decimal 更改为 int 是偶然的。如果你增加嵌套级别,你会发现它也对 int 失败。在我的 x64 机器上,此代码针对 intdecimal 进行编译,并使用大约 2.5GB 的内存,但是当内存使用量增长到 4GB 左右时,增加嵌套级别会导致溢出。

明确指定类型参数允许编译代码:

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))
                        )
                    )
                )
            );
    }
}

当您通过引入局部变量来减少嵌套时,编译器也可以工作:

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)
                )
            );
    }
}

关于C#编译器(csc.exe)内存溢出编译嵌套类型和Linq,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27523413/

相关文章:

visual-studio - 卸载使用 nuget.exe 安装的 nuget 软件包

apache - 如何为 Apache 打开以前被 Visual Studio 的服务器占用的端口 80?

c# - 哪个是处理读+写和只读的更好的 C# 类设计

c# - 在执行期间从 UI 向 BackgroundWorker 传递信息

c# - 在两个列表上使用联合没有按预期工作

c# - Linq 查询 Where() SQL % 等效

c# - 如何使用 Linq to Entities 从该集合中获取第一个值?

visual-studio - Visual Studio F# 交互窗口由哪个进程托管?

c# - 如何在满足条件之前禁用控件?

c# - 我可以使用 Linq 从 IEnumerables 构建元组吗?