gco*_*oll 4 c# memory foreach list
如果我从发布代码开始,这会更容易:
static void Main(string[] args)
{
List<double> testLst = new List<double>();
for (int i = 0; i < 20000000; i++) { testLst.Add(i); }
Run Code Online (Sandbox Code Playgroud)
我已经填充了一个包含20,000,000个元素的List.我在任务管理器中看到该进程正在使用~300MB.如果我使用foreach循环遍历列表:
foreach (var a in testLst.Take(10))
{
Console.WriteLine(a);
}
}
Run Code Online (Sandbox Code Playgroud)
内存使用率没有增加(我在Console.WriteLine上设置了一个断点,正如我所说,我正在使用任务管理器测量它).现在,如果我用ConcurrentBag替换List:
static void Main(string[] args)
{
ConcurrentBag<double> testCB = new ConcurrentBag<double>();
for (int i = 0; i < 20000000; i++) { testCB.Add(i); }
foreach (var a in testCB.Take(10))
{
Console.WriteLine(a);
}
}
Run Code Online (Sandbox Code Playgroud)
在foreach循环之前,内存使用量为450~500MB.问题是:为什么如果在foreach循环使用内部跳到~900MB?
我希望ConcurrentBag与List相比消耗更多内存,但我不明白为什么这么多内存被用于迭代.
(我在类似但不同的情况下使用ConcurrentBag,我知道在这种情况下使用它是没有意义的)
Luc*_*ski 10
从ConcurrentBag.GetEnumerator
文档(强调我的):
枚举表示行李内容的时刻快照.它不会反映
GetEnumerator
调用后对集合的任何更新.枚举器可以安全地与读取和写入包同时使用.
查看源代码,您可以看到它创建了一个包的副本:
public IEnumerator<T> GetEnumerator()
{
// Short path if the bag is empty
if (m_headList == null)
return new List<T>().GetEnumerator(); // empty list
bool lockTaken = false;
try
{
FreezeBag(ref lockTaken);
return ToList().GetEnumerator();
}
finally
{
UnfreezeBag(lockTaken);
}
}
Run Code Online (Sandbox Code Playgroud)
就像它的名字所暗示的那样,ToList()
返回一个List<T>
(它不是扩展方法,它是一个私有成员函数).
作为旁注,那条return new List<T>().GetEnumerator();
线并不漂亮......可能已经写了return Enumerable.Empty<T>().GetEnumerator();
.