C#:释放内存使用量

Rum*_*nsk 6 c# memory-management

我需要对一个开箱即用的问题执行一个漫长而繁重的过程。所以我将进程分为多个子进程。现在的问题是,在每个窗口执行之前如何释放内存。

\n\n

用一个例子来解释更容易。让我们看一下这个伪代码。

\n\n
1. Some earlier code to do other things\n2. Do\n3.     Raise a Task\n4.     If raised-task > 1000\n5.         Wait all raised task to finish\n6.         Release Memory\n7.     End If\n8. Wile Something not relevant\n
Run Code Online (Sandbox Code Playgroud)\n\n

有了这个想法,我开发了下一个方法,每次达到线程限制时都会执行该方法:

\n\n
List<Task> LTask();\n//It\'s not relevant, but this list is populate like\n//var task = Task.Run(() => something());\n//LTask.Add(task);\n\nprivate void waitForAll()\n{\n    //Break point 1\n    Task.WhenAll(LTasks).Wait();\n\n    LTasks.Clear();\n    LTasks = null;\n    GC.Collect();\n    GC.WaitForPendingFinalizers();\n\n    //Break point 2\n    LTasks = new List<Task>();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我预计记忆在某些值周围会保持恒定(有一些变化)。我是说:

\n\n
    \n
  1. 已达到线程限制
  2. \n
  3. BreakPoint 1 中使用 Visual Studio 诊断工具的内存使用情况快照 --> 100MB
  4. \n
  5. BreakPont 2 中 Visual Studio 诊断工具的内存使用情况快照 --> 100 MB。第一个问题,为什么这个没有减少?所有线程都已完成,我强制垃圾收集器执行。
  6. \n
\n\n

下次达到限制并执行此代码时,如果我再次拍摄快照,内存会不断增加:200、300,...

\n\n

这是诊断工具的捕获。每次到达断点 1 时都会拍摄奇数快照,而在断点 2 时拍摄偶数快照。

\n\n

在此输入图像描述

\n\n

第二个问题,这将继续无限制地增加,直到抛出Out of memory Exception?

\n\n

最后一个问题,有什么替代方案可以解决问题并释放内存吗?

\n\n

更新1: \n经过一些测试,并感谢评论,我开发了一个测试代码,以深入研究它。一定还涉及其他事情。请看下一段代码。内存继续无限增加。

\n\n
private List<Task> LTasks = new List<Task>();\nprivate void manageThreadholdLimit()\n{\n    waitForAll();\n    realeaseMemory();\n}\n\nprivate void waitForAll()\n{\n    Task.WhenAll(LTasks).Wait(); \n    LTasks.Clear();\n    LTasks = null;  \n}\nprivate void realeaseMemory()\n{   \n    GC.Collect();\n    GC.WaitForPendingFinalizers();\n\n    LTasks = new List<Task>();\n}\npublic void Main(){\n    int i = 0;\n\n    while (true)\n    {\n        i++;\n\n        var task = Task.Run(() => Thread.Sleep(100));\n        LTasks.Add(task);\n\n        //Si hemos alcanzado el m\xc3\xa1ximo de paralelismo, esperamos la conclusi\xc3\xb3n\n        if (i % 1000 == 0) manageThreadholdLimit();\n\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Rum*_*nsk 0

我想我找到了一个解释,感谢 @ScottChamberlain 在以下位置的回答:Why Garbage Collector does not Collect Tasks object

我认为内存会增加,因为 TaskScheduler 是静态的,并且尽管任务已完成,但仍然存储任务的引用。所以不断增加内存的是引用的数量,而不是每个任务本身的内存使用量。

我还没有弄清楚如何删除该引用,但是,作为替代解决方案,我可以重构使用线程的代码。例如,此代码是我的问题中“Update 1”的替代方案。并且内存稳定在18mb。

private static List<Thread> LThreads = new List<Thread>();
private static void manageThreadholdLimit()
{
    waitForAll();
    realeaseMemory();
}

private static void waitForAll()
{
    LThreads.ForEach(x => x.Join());
    LThreads.ForEach(x => x = null);
    LThreads.Clear();
    LThreads = null;
}
private static void realeaseMemory()
{


    GC.Collect();
    GC.WaitForPendingFinalizers();

    LTasks = new List<Task>();
    LThreads = new List<Thread>();
}
public static void Main(string[] args)
{
    int i = 0;

    while (true)
    {
        i++;

        var t = new Thread(() => Thread.Sleep(100));
        LThreads.Add(t);
        t.Start();

        if (i % 1000 == 0) manageThreadholdLimit();

    }
}
Run Code Online (Sandbox Code Playgroud)