【发布时间】:2019-11-20 18:12:20
【问题描述】:
我需要为一个开箱即用的问题执行一个冗长的过程。所以我把这个过程分成了多个子过程。现在的问题是,如何在每个窗口执行之前释放内存。
用一个例子更容易解释。我们来看看这个伪代码。
1. Some earlier code to do other things
2. Do
3. Raise a Task
4. If raised-task > 1000
5. Wait all raised task to finish
6. Release Memory
7. End If
8. Wile Something not relevant
有了这个想法,我开发了下一个方法,每次达到线程限制时都会执行:
List<Task> LTask();
//It's not relevant, but this list is populate like
//var task = Task.Run(() => something());
//LTask.Add(task);
private void waitForAll()
{
//Break point 1
Task.WhenAll(LTasks).Wait();
LTasks.Clear();
LTasks = null;
GC.Collect();
GC.WaitForPendingFinalizers();
//Break point 2
LTasks = new List<Task>();
}
我预计内存在某些值附近会保持不变(有一些变化)。我的意思是:
- 已达到线程限制
- BreakPoint 1 中使用 Visual Studio 诊断工具的内存使用快照 --> 100MB
- BreakPont 2 中使用 Visual Studio 诊断工具的内存使用快照 --> 100 MB。 第一个问题,为什么没有减少?所有线程都结束了,我强制垃圾收集器执行。
下次达到限制并执行此代码时,如果我再次快照,内存不断增加:200、300、...
这是一个诊断工具的捕获。每次到达断点 1 时拍摄奇数快照,并在断点 2 时拍摄偶数快照。
第二个问题,这将继续无限增加,直到抛出 Out of memory Exception?
最后一个问题,有什么办法可以解决问题,释放内存?
更新 1: 经过一些测试,多亏了 cmets,我开发了一个测试代码来深入研究它。必须涉及其他事情。请看下一段代码。内存继续无限增长。
private List<Task> LTasks = new List<Task>();
private void manageThreadholdLimit()
{
waitForAll();
realeaseMemory();
}
private void waitForAll()
{
Task.WhenAll(LTasks).Wait();
LTasks.Clear();
LTasks = null;
}
private void realeaseMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
LTasks = new List<Task>();
}
public void Main(){
int i = 0;
while (true)
{
i++;
var task = Task.Run(() => Thread.Sleep(100));
LTasks.Add(task);
//Si hemos alcanzado el máximo de paralelismo, esperamos la conclusión
if (i % 1000 == 0) manageThreadholdLimit();
}
}
【问题讨论】:
-
可能,它保持对线程内对象的引用。可以发一下任务代码吗?对于第二个问题:是的,它会在内存不足异常时增加。
-
很遗憾,我无法粘贴任务代码,这是一个繁重的过程,并且包含一些明智的信息。但是,所有引发的任务都执行相同的功能,不接收任何参数。因此,当它在
LTask.Clear(); LTask = null;中被取消引用时,它在内部声明的所有对象也应该被取消引用。 -
您能否在 TaskManager 或 Process Explorer(如果有)中查看您正在调试的这个进程?查找内存和线程数。也许尝试在发布模式下运行应用程序来执行此操作,因为垃圾收集器可能会在那里更快地收集对象。
-
我个人遇到了这个问题,通过代码将事件附加到 Winforms 对象,并且在关闭表单之前不卸载它们。同样就个人而言,我使用内存分析器解决了问题(如果您愿意,可以免费试用memprofiler.com)。它告诉了什么它被什么阻止了。
-
你是否在这段代码中使用了事件?
标签: c# memory-management