问题描述
.NET 4的ThreadLocal<>实现IDisposable。但似乎调用Dispose()并不真正释放引用到线程正在举行本地对象。
.Net 4. ThreadLocal<> implements IDisposable. But it seems that calling Dispose() doesn't actually release references to thread local objects being held.
这code重新产生此问题:
This code reproduces the problem:
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
namespace ConsoleApplication2
{
class Program
{
class ThreadLocalData
{
// Allocate object in LOH
public int[] data = new int[10 * 1024 * 1024];
};
static void Main(string[] args)
{
// Stores references to all thread local object that have been created
var threadLocalInstances = new List<ThreadLocalData>();
ThreadLocal<ThreadLocalData> threadLocal = new ThreadLocal<ThreadLocalData>(() =>
{
var ret = new ThreadLocalData();
lock (threadLocalInstances)
threadLocalInstances.Add(ret);
return ret;
});
// Do some multithreaded stuff
int sum = Enumerable.Range(0, 100).AsParallel().Select(
i => threadLocal.Value.data.Sum() + i).Sum();
Console.WriteLine("Sum: {0}", sum);
Console.WriteLine("Thread local instances: {0}", threadLocalInstances.Count);
// Do our best to release ThreadLocal<> object
threadLocal.Dispose();
threadLocal = null;
Console.Write("Press R to release memory blocks manually or another key to proceed: ");
if (char.ToUpper(Console.ReadKey().KeyChar) == 'R')
{
foreach (var i in threadLocalInstances)
i.data = null;
}
// Make sure we don't keep the references to LOH objects
threadLocalInstances = null;
Console.WriteLine();
// Collect the garbage
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine("Garbage collected. Open Task Manager to see memory consumption.");
Console.Write("Press any key to exit.");
Console.ReadKey();
}
}
}
主题本地数据存储的引用,一个大对象。 GC不会收集这些大对象,如果引用没有手动调零。我用任务管理器来观察内存消耗。我也运行内存分析器。我做了一个快照,垃圾收集后。探查表明,泄漏的对象根植通过的GCHandle和被分配在这里:
Thread local data stores a reference to a large object. GC doesn't collect these large objects if references are not nulled manually. I used Task Manager to observe memory consumption. I also run memory profiler. I made a snapshot after garbage was collected. The profiler showed that leaked object is rooted by GCHandle and was allocated with here:
mscorlib!System.Threading.ThreadLocal<T>.GenericHolder<U,V,W>.get_Boxed()
mscorlib!System.Threading.ThreadLocal<T>.get_Value()
ConsoleApplication2!ConsoleApplication2.Program.<>c__DisplayClass3.<Main>b__2( int ) Program.cs
这似乎是在ThreadLocal中℃的缺陷;>设计。与存储所有分配对象为进一步清理诀窍是丑陋的。关于如何解决的任何想法?
That seems to be a flaw in ThreadLocal<> design. The trick with storing all allocated objects for further cleanup is ugly. Any ideas on how to work around that?
推荐答案
运行.Net的4.5 DP,我看不出之间pressing 研究骨节病>或不在您的应用程序的任何差异。如果确实是内存泄漏4.0,现在看来,这是固定的。
Running on .Net 4.5 DP, I don't see any difference between pressing or not in your application. If there actually was a memory leak in 4.0, it seems it was fixed.
(4.5是一个就地更新,所以我不能在同一台计算机上测试4.0,对不起。)
(4.5 is a in-place update, so I can't test 4.0 on the same computer, sorry.)
这篇关于ThreadLocal的&LT;&GT;和内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!