1

我正在为一些异步代码编写一个实用程序类,并且我想确保我不会在设计中造成内存泄漏。假设我的代码执行类似于下面的类。(显然你不会编写像这样工作的代码,但我有几个代码路径都汇聚成一个底层函数,其中一个代码路径有效地做到了这一点)。代码中的关键点是的代码中没有任何内容包含对 theTaskCompletionSource或其Task.

假设 Foo 实例是根据需要创建的,并且不是永久植根的。tcs.Task扎根了吗?更重要的是,假设request永远不会完成,因此不会设置结果。会tcs.Task永远闲逛吗?接续任务呢?或者,它们的生命周期是否依赖于 Foo 对象,并且当 Foo 实例被 GC-ed 时它们会消失?

class Foo
{
    public void Bar(Action<Action<object>> request, Action<T> callback)
    {
        var tcs = new TaskCompletionSource<object>();
        request(result => tcs.SetResult(result));  // this runs asynchronously
        tcs.Task.ContinueWith(task => callback(task.Result));
    }
}
4

1 回答 1

0

假设 Foo 实例是根据需要创建的,并且不是永久植根的。tcs.Task 是否已植根?

不,没有理由tcs.Task被排除在Bar和之外request。由于您传入tcs一个 lambda,它将被“关闭”,即将创建一个对象并将其传递给Barand request。一旦这两个例程都结束,tcs.Task将变得无法访问且易于收集。

更重要的是,假设请求永远不会完成,所以结果不会被设置。tcs.Task 会永远存在吗?

如果request永远无法完成,那么您遇到的问题不仅仅是tcs.Task. 这意味着整个线程将被阻塞并保持活动状态,直到您的进程结束,其所有堆栈(1 MB)以及植根于该堆栈的所有对象图。如果您还获得非托管资源,则损害会更严重。如果request因异常而失败,它将结束,其堆栈将被释放,并且以它为根的对象将变得易于收集。

于 2020-05-27T11:33:43.830 回答