C# 没有对任务的引用是否会导致内存泄漏?
考虑以下代码段:C# 没有对任务的引用是否会导致内存泄漏?,c#,.net,memory-leaks,task-parallel-library,C#,.net,Memory Leaks,Task Parallel Library,考虑以下代码段: public void Do() { .... Task.Delay(5000).ContinueWith(t => DoSomething()); .... } 假设Do方法在Delay任务完成之前完成执行,并且DoSomething不可取消 没有对ContinueWith方法返回的任务进行引用的事实是否会导致某种内存泄漏 任务将在线程池线程上执行,一旦任务完成,线程将返回到线程池供其他任务使用 线程池线程在空闲一段时间后(我认为默认情况下大约45秒
public void Do()
{
....
Task.Delay(5000).ContinueWith(t => DoSomething());
....
}
假设Do
方法在Delay
任务完成之前完成执行,并且DoSomething
不可取消
没有对
ContinueWith
方法返回的任务
进行引用的事实是否会导致某种内存泄漏 任务将在线程池线程上执行,一旦任务完成,线程将返回到线程池供其他任务使用
线程池线程在空闲一段时间后(我认为默认情况下大约45秒)被回收
因此,线程池持有对它的引用这一事实将防止它被垃圾收集
我想唯一需要注意的是,主应用程序线程必须运行。例如,如果在控制台应用程序中运行上述代码,则执行将在任务之前完成,因此任务将永远不会运行
简而言之,否-该代码不会导致内存泄漏。您可以通过创建未收集的新任务来泄漏(托管)内存吗?是。 保留对它的引用(或不保留引用)对收集它有任何影响吗?
通常*不是。 有两种类型的任务:承诺(异步)任务和委托(同步)任务
- 承诺任务(如
)通常不会被收集,因为某些东西会保留对它的引用,以便它可以在需要时更改其状态(在Task.Delay
中,当延迟结束时,需要完成Task.Delay
任务的是内部
)计时器
- 委托任务()由运行它们的线程(和
)引用TaskScheduler
计时器
引用Promise任务
,该任务反过来引用委托任务
(该任务尚未计划,并且没有与其关联的线程)。5秒后,计时器
完成任务。延迟
任务,该任务依次安排DoSomething
继续,因此线程将引用它
如果DoSomething
从未完成,则内存泄漏(非常小),如果确实完成,则不会
*您可以创建仅由您引用的任务(两种类型),当您不再引用它们时,它们可以由
GC
收集。因此,尽管如此:
static void Main()
{
while (true)
{
Task.Delay(int.MaxValue);
}
}
将在几秒钟内导致OutOfMemoryException
,这可能会永远运行:
static void Main()
{
while (true)
{
new Task(() => Thread.Sleep(int.MaxValue)); // No thread as the task isn't started.
Task.Delay(-1); // No Timer as the delay is infinite.
}
}
如果你的代码只是
Task.Delay(5000),你可以说同样的话代码>-“未维护对返回任务的引用”,我很确定这不会泄漏。我认为即使您愿意,也不可能在托管上下文中泄漏内存。当引用类型的实例没有引用时,GC最终会来收集它。虽然不是泄漏,但您的任务将是“未观察到的”,如果抛出任何异常,未观察到的任务将导致混乱。它只能由任务终结器检测到,任务终结器在垃圾收集过程中以无法控制的时间运行。所以我还是建议重写你的代码。谢谢,很好的解释。那么不来自线程池的长时间运行的任务呢?您是指长时间运行标志吗?如果是这样,这只会向调度程序提供一个提示,提示它可能希望在非线程池线程上执行任务。即使它确实在非线程池线程上执行,它仍然是一个托管线程,并且在执行完成后将被清除。此外,Stephen Cleary在本文中指出,在大多数情况下,您可能不需要LongRunning标志,因为调度器能够在0.5秒内调整到任何长时间运行的任务:task.Delay(-1)
也会导致内存泄漏,这与task.Delay(int.MaxValue)
(至少在.NET 4.6上是这样)@marchewek你认为这会泄露什么?哪一类的实例?