Rum*_*nsk 6 c# memory-management
我需要对一个开箱即用的问题执行一个漫长而繁重的过程。所以我将进程分为多个子进程。现在的问题是,在每个窗口执行之前如何释放内存。
\n\n用一个例子来解释更容易。让我们看一下这个伪代码。
\n\n1. 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\nRun Code Online (Sandbox Code Playgroud)\n\n有了这个想法,我开发了下一个方法,每次达到线程限制时都会执行该方法:
\n\nList<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}\nRun Code Online (Sandbox Code Playgroud)\n\n我预计记忆在某些值周围会保持恒定(有一些变化)。我是说:
\n\n下次达到限制并执行此代码时,如果我再次拍摄快照,内存会不断增加:200、300,...
\n\n这是诊断工具的捕获。每次到达断点 1 时都会拍摄奇数快照,而在断点 2 时拍摄偶数快照。
\n\n\n\n第二个问题,这将继续无限制地增加,直到抛出Out of memory Exception?
最后一个问题,有什么替代方案可以解决问题并释放内存吗?
\n\n更新1: \n经过一些测试,并感谢评论,我开发了一个测试代码,以深入研究它。一定还涉及其他事情。请看下一段代码。内存继续无限增加。
\n\nprivate 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}\nRun Code Online (Sandbox Code Playgroud)\n
我想我找到了一个解释,感谢 @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)