任务不会被破坏并填满内存

Posted

技术标签:

【中文标题】任务不会被破坏并填满内存【英文标题】:Tasks are not getting destroyed and filling up memory 【发布时间】:2022-01-04 02:26:08 【问题描述】:

考虑这个将整数放入列表的简单示例程序:

void Main()

    Experiment experiment = new();
    var task = Task.Run(experiment.Start);


public class Experiment

    public async Task Start()
    
        List<int> values = new();

        for (int i = 0; i < 1000000000; i++)
            values.Add(i);

        await Task.CompletedTask;
    

运行时,它使用大约 7 GB 的内存。但随后这些数据就停留在那里。即使我清除列表或将其设置为空,程序仍然占用 7 GB。当我再次运行它时,RAM使用率突然下降到10 MB,然后又猛增到7 GB,让我觉得只有用这种方法开始一个新任务,数据才会真正释放。

为什么任务完成后内存没有释放?我不明白为什么列表不是临时的并且一直占用内存。我做错了什么?

【问题讨论】:

尝试等待一段时间。 GC 将运行并释放内存。出于测试目的,您可以尝试使用 GC.Collect() 强制 GC,但不要在生产中使用强制 GC。 【参考方案1】:

.NET 使用垃圾回收来释放未使用的内存。

垃圾收集更有可能在内存不足时运行。但除此之外,没有办法预测它什么时候运行,或者你的内存什么时候释放。

在任何一种情况下,一旦不再需要内存(或者在您的情况下完成任务时),垃圾收集都不会运行。

这是正常行为。当您的内存不足时,垃圾收集应该尽快处理它。

【讨论】:

垃圾收集器释放了空间......至少其中一些。我的实际程序不做任何事情就使用 30 MB,然后增加到 7000 MB。当我调用 GC.Collect() 时,它会下降到 300 MB。我已经让程序运行了几个小时,它再也不会下降到 30 MB。这是为什么?如果所有垃圾都已收集,那么 270 MB 的 RAM 使用量来自哪里? 垃圾收集器只会释放程序不再可以访问的内存。您发布的代码非常不寻常。您将返回的Task 分配给一个变量,但从不等待它。无论如何,如果内存没有被回收,您的代码可能仍然持有对它的引用。【参考方案2】:

也许在主程序中添加 task.Wait()。我认为在任务完成之前主程序退出。也许任务在退出时仍然被引用,因此减慢了 gc。

【讨论】:

以上是关于任务不会被破坏并填满内存的主要内容,如果未能解决你的问题,请参考以下文章

RuntimeError:事件循环已关闭任务被破坏但它正在等待 Discord Python

Discord 机器人,任务被破坏

取消 asyncio 任务导致“任务被破坏但它处于挂起状态”

ASYNCIO:[错误] 任务被破坏,但它处于挂起状态

如何修复'错误:asyncio:任务已被破坏,但它正在等待处理! Python中的错误

Python36 Discord Bot:任务已被破坏,但处于待处理状态