[英]Can passing context to static methods cause memory leaks in Android?
[英]Can TaskCompletionSource that never complete cause memory leaks?
我有一個組件,它可以執行長時間的異步操作,並且可以在這些操作完成之前被銷毀。 在這種情況下,我只想停止運行這些操作並忘記它們,沒有任何例外。 我有下一個例子:
private CancellationTokenSource destroyTokenSource = new CancellationTokenSource();
private async void RunExample()
{
await LongAction().MuteOnDestroy(destroyTokenSource.Token);
// ... actions that should not be performed with destroyed object
}
private async Task<bool> LongAction()
{
// some very long actions
return true;
}
// ...
public static class TaskExtension
{
public static Task<T> MuteOnDestroy<T>(this Task<T> task, CancellationToken destroyToken)
{
var promise = new TaskCompletionSource<T>();
task.ContinueWith(t =>
{
if (!destroyToken.IsCancellationRequested)
{
switch (t.Status)
{
case TaskStatus.Canceled:
promise.SetCanceled();
break;
case TaskStatus.Faulted:
promise.SetException(t.Exception!);
break;
case TaskStatus.RanToCompletion:
promise.SetResult(t.Result);
break;
}
}
}, TaskContinuationOptions.ExecuteSynchronously);
return promise.Task;
}
}
我假設永遠不會完成的異步方法(在本例中為RunExample
方法)( destroyToken.IsCancellationRequested == true
)會導致內存泄漏,但我不確定,因為我不知道“永遠等待”方法的延續在哪里被儲存了。
它會導致內存泄漏嗎?
是的,你絕對造成泄漏。 TPL 將確保 GC 不會清理任何正在進行的任務,並且所有這些任務都將引用其延續委托,而這些委托本身通常會引用更多對象。 如果允許 GC 清理這些對象,那將是一個問題,因為所有代碼都可以並且很可能最終會運行。 GC 的全部意義在於它不會清除對可以從可以執行的代碼訪問的對象的引用。
問題是,如果取消令牌在您包裝的任務完成之前被取消,則您嘗試使用取消令牌包裝任務的嘗試永遠不會提前完成。 它會等到操作正常完成以將包裝的任務標記為已取消。
幸運的是,正確解決這個問題實際上比您現有的解決方案更簡單,因為您可以利用現有的 TPL 工具在這種情況下完成大部分艱苦的工作。
鏈接的解決方案將導致任務更快地被標記為取消,因此長時間運行的任務本身仍然會保持對其使用的所有對象的引用,直到它完成,但利用取消令牌的延續將能夠被盡快取消並釋放他們持有的任何資源。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.