在使用 Visual Studio 2013 性能分析工具分析我的代码的 .NET 内存分配时,我注意到某个函数分配了很多字节(因为它在一个大循环中被调用)。但是在分析报告中突出显示的函数中,我不明白为什么它会分配任何内存。
为了更好地理解发生了什么,我隔离了导致分配的代码。这类似于下面的 LinqAllocationTester 类。
一旦我在该函数中注释掉 LINQ 代码(在测试代码路径中从未执行过),就不再分配内存。NonLinqAllocationTester 类模拟了这种行为。将 LINQ 代码替换为普通循环也不会导致内存分配。
如果我在下面的测试代码上运行 .NET 内存分配测试,它会显示 LinqAllocationTester 导致了 100,000 次分配(每次调用 1 次),而 NonLinqAllocationTester 则没有。 请注意,useLinq 始终为 false,因此 LINQ 代码本身实际上从未被执行过。
Function Name | Inclusive | Exclusive | Inclusive | Exclusive
| Allocations | Allocations | Bytes | Bytes
-------------------------------------------------------------------------------------
LinqAllocationTester.Test(int32) | 100.000 | 100.000 | 1.200.000 | 1.200.000
Program.Main(string[]) | 100.000 | 0 | 1.200.000 | 0
那么为什么未执行的 LINQ 代码会导致内存分配?除了避免使用 LINQ 函数外,是否有其他方法可以防止这种情况发生?
class Program {
static void Main(string[] args) {
List<int> values = new List<int>() { 1, 2, 3, 4 };
LinqAllocationTester linqTester = new LinqAllocationTester(false, values);
NonLinqAllocationTester nonLinqTester = new NonLinqAllocationTester(false, values);
for (int i = 0; i < 100000; i++) {
linqTester.MaxDifference(i);
}
for (int i = 0; i < 100000; i++) {
nonLinqTester.MaxDifference(i);
}
}
}
internal class LinqAllocationTester {
private bool useLinq;
private List<int> values;
public LinqAllocationTester(bool useLinq, List<int> values) {
this.useLinq = useLinq;
this.values = values;
}
public int MaxDifference(int value) {
if (useLinq) {
return values.Max(x => Math.Abs(value - x));
} else {
int maxDifference = int.MinValue;
foreach (int value2 in values) {
maxDifference = Math.Max(maxDifference, Math.Abs(value - value2));
}
return maxDifference;
}
}
}
internal class NonLinqAllocationTester {
private bool useLinq;
private List<int> values;
public NonLinqAllocationTester(bool useLinq, List<int> values) {
this.useLinq = useLinq;
this.values = values;
}
public int MaxDifference(int value) {
if (useLinq) {
return 0;
} else {
int maxDifference = int.MinValue;
foreach (int value2 in values) {
maxDifference = Math.Max(maxDifference, Math.Abs(value - value2));
}
return maxDifference;
}
}
}