更新,好點的@SriramSakthivel,原來我已經回答了一個非常類似的問題:
Why does GC collects my object when I have a reference to it?
所以我標記這個作爲一個社區的wiki。
但是,讓我們說的setResult(..)不會被調用,並 someClassInstance停止被引用,並進行垃圾回收。 這是否會造成內存泄漏?或.Net自動神奇地知道 調用上下文需要處置?
如果由調用上下文你指的是編譯器生成的狀態機對象(代表async
方法的狀態),然後是的,這的確會敲定。
例子:
static void Main(string[] args)
{
var task = TestSomethingAsync();
Console.WriteLine("Press enter to GC");
Console.ReadLine();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
GC.WaitForFullGCComplete();
GC.WaitForPendingFinalizers();
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
static async Task TestSomethingAsync()
{
using (var something = new SomeDisposable())
{
await something.WaitForThingAsync();
}
}
class SomeDisposable : IDisposable
{
readonly TaskCompletionSource<string> _tcs = new TaskCompletionSource<string>();
~SomeDisposable()
{
Console.WriteLine("~SomeDisposable");
}
public Task<string> WaitForThingAsync()
{
return _tcs.Task;
}
public void Dispose()
{
Console.WriteLine("SomeDisposable.Dispose");
GC.SuppressFinalize(this);
}
}
輸出:
Press enter to GC
~SomeDisposable
Press enter to exit
IMO,這種行爲是合乎邏輯的,但它仍然可能是一個有點意外的是something
被最終確定,儘管事實它的範圍從未結束(因此它的SomeDisposable.Dispose
從未被稱爲)並且由TestSomethingAsync
返回的10個仍然存在並且在Main
中被引用。
編碼系統級別的異步內容時,這可能會導致一些模糊的錯誤。在async
方法之外的任何OS互操作回調中使用GCHandle.Alloc(callback)
都非常重要。在async
方法的末尾單獨做GC.KeepAlive(callback)
是無效的。我在細節寫這個位置:
Async/await, custom awaiter and garbage collector
在一個側面說明,還有另一種C#狀態機:與return yield
的方法。有趣的是,與IEnumerable
或IEnumerator
一起,它也實現了IDisposable
。調用其Dispose
會展開任何using
和finally
語句(即使不完全枚舉序列的情況下):
static IEnumerator SomethingEnumerable()
{
using (var disposable = new SomeDisposable())
{
try
{
Console.WriteLine("Step 1");
yield return null;
Console.WriteLine("Step 2");
yield return null;
Console.WriteLine("Step 3");
yield return null;
}
finally
{
Console.WriteLine("Finally");
}
}
}
// ...
var something = SomethingEnumerable();
something.MoveNext(); // prints "Step 1"
var disposable = (IDisposable)something;
disposable.Dispose(); // prints "Finally", "SomeDisposable.Dispose"
與此不同,與async
方法有控制的using
和finally
的unwiding的直接方式。
TCS是一個孤立的對象。無法訪問時收集。其任務沒有引用TCS,因此您可以在內存中沒有任何相應的TCS的情況下執行不可完成的任務。如果該任務不被引用,它也會被收集。 – usr 2015-02-01 09:48:04