Dan*_*don 8 .net c# garbage-collection memory-management
以下代码是我看到的问题的简化示例.由于字典太大,此应用程序在抛出异常之前会消耗大约4GB的内存.
class Program
{
static void Main(string[] args)
{
Program program = new Program();
while(true)
{
program.Method();
Console.ReadLine();
}
}
public void Method()
{
WasteOfMemory memory = new WasteOfMemory();
Task tast = new Task(memory.WasteMemory);
tast.Start();
}
}
public class WasteOfMemory
{
public void WasteMemory()
{
Dictionary<string, string> aMassiveList = new Dictionary<string, string>();
try
{
long i = 0;
while (true)
{
aMassiveList.Add(i.ToString(), "I am a line of text designed to waste space.... I am exceptionally useful........");
i++;
}
}
catch(Exception e)
{
Console.WriteLine("I have broken myself");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都符合预期,尽管我们目前无法解决的问题是何时应从CLR中释放此内存.
我们让任务完成,然后模拟了内存过载情况,但字典消耗的内存不会被释放.由于操作系统内存不足,是不是要对CLR施加压力才能释放内存?
然而,更令人困惑的是,如果我们等到任务完成,然后按Enter键再次运行任务,内存被释放,所以很明显以前的字典已经被垃圾收集了(不是吗?).
那么,为什么内存没有被释放?我们怎样才能让CLR释放内存?
任何解释或解决方案将不胜感激.
编辑:在回复之后,尤其是贝斯卡,很明显我对这个问题的描述并不是最清楚的,所以我会尽力澄清.
对不起,代码可能不是最好的例子!尝试复制该问题是一段快速的原始代码.
这里使用字典来复制我们有一个大型自定义数据对象的事实,它填充了我们大量的内存,然后在任务完成后就不会释放.
在示例中,字典填充字典的限制,然后抛出异常,它不会永远填充!这在我们的内存已满之前就已存在,并且它不会导致OutOfMemoryException.因此结果是内存中的大对象,然后任务完成.
此时我们希望字典超出范围,因为任务和方法'方法'都已完成.因此,我们希望字典被垃圾收集并回收内存.实际上,在再次调用"Method",创建新的WasteOfMemory实例并启动新任务之前,不会释放内存.
希望这会澄清一点问题
该垃圾收集器只释放那些不再使用的是其没有指针指向这些对象在内存中的位置.
(1)你的程序无限运行而没有终止
(2)你永远不会改变指向你字典的指针,所以GC肯定没有理由触及字典.
所以对我来说你的程序是做究竟什么是应该做的.
好吧,我一直在关注这个......我认为有几个问题,其中一些人们已经触及,但我认为没有回答真正的问题(诚然,我花了一段时间才认识到这一点,而且我'即使现在我也不确定我是否在回答你想要的。)
这一切都符合预期,尽管我们目前无法确定何时应从 CLR 释放该内存。
正如其他人所说,当任务运行时,字典不会被释放。它正在被使用。它会变大,直到内存耗尽。我很确定你明白这一点。
我们已经让任务完成了,然后模拟了内存过载的情况,但是字典消耗的内存并没有被释放。当OS内存不足时,这不是给CLR施加压力来释放内存吗?
我认为,这才是真正的问题。
如果我理解正确的话,你是说你设置它是为了填充内存。然后,在它崩溃之后(但在您按回车键开始新任务之前),您正在尝试该程序之外的其他操作,例如在 Windows 中运行其他程序以尝试让 GC 收集内存,对吗?希望操作系统能够与 GC 对话,并开始迫使它做它的事情。
然而,更令人困惑的是,如果我们等到任务完成,然后按回车键再次运行任务,内存就会被释放,所以显然之前的字典已被垃圾收集(不是吗?)。
我想你回答了你自己的问题......它不一定被释放,直到你点击返回开始新任务。新任务需要内存,因此它进入 GC,GC 愉快地从前一个任务中收集内存,该任务现在已经结束(在从完整内存中抛出之后)。
那么,为什么内存没有被释放呢?那么如何才能让CLR释放内存呢?
我不知道你可以强制GC释放内存。一般来说,它会在需要时执行此操作(尽管某些黑客类型可能知道一些巧妙的方法来强制执行。)当然,.NET 决定何时运行 GC,并且由于程序只是坐在那里时什么也没有发生,它很可能决定不需要这样做。至于操作系统是否可以迫使GC运行,从你的测试来看,答案似乎是“不”。也许有点违反直觉。
这就是你想要达到的目的吗?