【发布时间】:2018-09-11 11:25:42
【问题描述】:
我正在我的窗口中执行异步任务:
private async Task LoadData()
{
// Fetch data
var data = await FetchData();
// Display data
// ...
}
窗口在单独的线程中启动:
// Create and run new thread
var thread = new Thread(ThreadMain);
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.CurrentCulture = Thread.CurrentThread.CurrentCulture;
thread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
thread.Start();
private static void ThreadMain()
{
// Set synchronization context
var dispatcher = Dispatcher.CurrentDispatcher;
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(dispatcher));
// Show window
var window = new MyWindow();
window.ShowDialog();
// Shutdown
dispatcher.InvokeShutdown();
}
当windows关闭时,线程当然结束了,这样就好了。
现在 - 如果在 FetchData 完成之前发生这种情况,我会得到内存泄漏。
似乎FetchData 一直在等待,而Task.s_currentActiveTasks 静态字段将永远保留我的窗口实例:
保留路径
System.Collections.Generic.Dictionary.entries -> System.Collections.Generic.Dictionary+Entry[37] 在 [17].值-> System.Threading.Tasks.Task.m_continuationObject -> System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.m_action -> System.Action._target -> System.Runtime.CompilerServices.AsyncMethodBuilderCore+ContinuationWrapper.m_continuation -> System.Action._target -> System.Runtime.CompilerServices.AsyncMethodBuilderCore+ContinuationWrapper.m_continuation -> System.Action._target -> ...
如果我理解正确,如果/当 FetchData 完成时,继续应该在窗口实例目标和线程上继续,但自从线程完成后就不会发生这种情况。
有什么解决办法,这种情况下如何避免内存泄漏?
【问题讨论】:
-
“窗口在单独的线程中启动” - 为什么?你永远不需要它,async/await 让避免它变得更容易。
-
@HenkHolterman 因为用户需要能够使用不同的功能,而不需要每个功能都通过模态对话框阻塞所有其他功能。
-
所以你使用线程将
.ShowDialog()还原为.Show()? -
认为这里的真正问题是 - 当等待的任务由于原始线程/同步上下文不复存在而无法恢复时,会发生什么情况?
-
您的第一个错误是创建另一个 sta 线程并将其用于任何 UI。不要那样做。这是一个非常糟糕的主意,它会导致更多值得的问题。
标签: c# wpf multithreading async-await