巡回グラフで使用されたとき、私はちょうど私が説明することはできませんSystem.Threading.ThreadLocal<T>
に関するガベージコレクタのこの奇妙な行動」に出会いました。通常の状況では、ThreadLocal<T>
インスタンスは、オブジェクトが循環オブジェクトグラフの一部である場合を除いて、適切に配置されていなくても、スコープから外れるとガベージコレクションされます。メモリリークのThreadLocal <T>が
次の例では、問題を示しています。
public class Program
{
public class B { public A A; }
public class A { public ThreadLocal<B> LocalB; }
private static List<WeakReference> references = new List<WeakReference>();
static void Main(string[] args) {
for (var i = 0; i < 1000; i++)
CreateGraph();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
// Expecting to print 0, but it prints 1000
Console.WriteLine(references.Count(c => c.IsAlive));
}
static void CreateGraph() {
var a = new A { LocalB = new ThreadLocal<B>() };
a.LocalB.Value = new B { A = a };
references.Add(new WeakReference(a));
// If either one of the following lines is uncommented, the cyclic
// graph is broken, and the programs output will become 0.
// a.LocalB = null;
// a.LocalB.Value = null;
// a.LocalB.Value.A = null;
// a.LocalB.Dispose();
}
}
Dispose
を呼び出していないことDispose
が呼び出されていない場合でも、良い習慣ではありませんが、それは最終的に(ファイナライザを呼び出すことによって)リソースをクリーンアップするためにCLRのデザインだが。
なぜThreadLocal
振る舞いは、この点で異なって行い、適切に巡回グラフの場合に配置されていないときに、メモリリークを引き起こす可能性がありますか?これは設計によるものですか?もしそうなら、これはどこに文書化されていますか?または、これはCLRのGCのバグですか? (.NET 4.5でテスト)
。
[David Kean](https://twitter.com/davkean)はこれがバグであることを確認しました。 – Steven
[クリック](https://mobile.twitter.com/davkean/status/655067698511024128)。 – Steven