我发现了一种使用 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 机器上,此代码针对 int
和 decimal
进行编译,并使用大约 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/