Csharp/C#教程:任务完成后C#不释放内存分享


任务完成后C#不释放内存

以下代码是我看到的问题的简化示例。 由于字典太大,此应用程序在抛出exception之前会占用大约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 aMassiveList = new Dictionary(); 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"); } } } 

这一切都符合预期,尽管我们目前无法解决的问题是何时应从CLR中释放此内存。

我们让任务完成,然后模拟内存过载情况,但字典消耗的内存不会被释放。 由于操作系统内存不足,是不是要对CLR施加压力才能释放内存?

然而,更令人困惑的是,如果我们等到任务完成,然后再次按Enter键再次运行任务,内存被释放,所以很明显以前的字典已经被垃圾收集了(不是吗?)。

那么,为什么内存没有被释放? 我们怎样才能让CLR释放内存?

任何解释或解决方案将不胜感激。

编辑:在回复之后,尤其是贝斯卡,很明显我对这个问题的描述并不是最清楚的,所以我会尽力澄清。

代码可能不是最好的例子,抱歉! 尝试复制该问题是一段快速的原始代码。

这里使用字典来复制我们有一个大型自定义数据对象的事实,它填充了我们大量的内存,然后在任务完成后就不会释放。

在该示例中,字典填充字典的限制然后抛出exception,它不会永远填充! 这在我们的内存已满之前就已存在,并且它不会导致OutOfMemoryException。 因此结果是内存中的大对象,然后任务完成。

此时我们希望字典超出范围,因为任务和方法’方法’都已完成。 因此,我们希望字典被垃圾收集并回收内存。 实际上,在再次调用“Method”,创建新的WasteOfMemory实例并启动新任务之前,不会释放内存。

希望这会澄清一下这个问题

好吧,我一直在关注这个…我认为有一些问题,其中一些人已经触及,但我认为没有回答真正的问题(诚然,我花了一些时间来认识,而且我’我不确定我现在还在回答你想要的东西。)

这一切都符合预期,尽管我们目前无法解决的问题是何时应从CLR中释放此内存。

正如其他人所说,当任务正在运行时,字典将不会被释放。 它被使用了。 它会变得更大,直到你的内存耗尽。 我很确定你明白这一点。

我们让任务完成,然后模拟内存过载情况,但字典消耗的内存不会被释放。 由于操作系统内存不足,是不是要对CLR施加压力才能释放内存?

我认为,这是真正的问题。

如果我理解正确的话,你就是说你设置它来填补内存。 然后,在它崩溃之后(但是在你返回开始一个新任务之前)你正在尝试这个程序之外的其他东西,比如在Windows中运行其他程序试图让GC收集内存,对吧? 希望操作系统能够与GC通信,并开始向它施加压力以实现它的目的。

然而,更令人困惑的是,如果我们等到任务完成,然后再次按Enter键再次运行任务,内存被释放,所以很明显以前的字典已经被垃圾收集了(不是吗?)。

我认为你回答了自己的问题……在你回到开始一项新任务之前,它并没有被释放。 新任务需要内存,因此它进入GC,GC很乐意收集上一个任务的内存,该任务现在已经结束(从完全内存中抛出后)。

那么,为什么内存没有被释放? 我们怎样才能让CLR释放内存?

我不知道你可以强制GC释放内存。 一般来说,它会在它需要时执行它(虽然一些黑客类型可能知道一些光滑的方式来强制它的手。)当然,.NET决定何时运行GC,并且因为当程序只是坐在那里时没有发生任何事情,它很可能决定它不需要。 至于操作系统是否可以强制GC运行,从你的测试看来答案是“不”。 有点反直觉。

那是你想要的吗?

垃圾收集器仅释放内存中不再使用的位置,这些位置是没有指向它们的指针的对象。

(1)你的程序无限运行而没有终止

(2)你永远不会改变指向你字典的指针,所以GC肯定没有理由触及字典。

所以对我来说,你的程序正在做它应该做的事情。

内存未被释放,因为范围aMassiveList永远不会完成。 当函数返回时,它会释放在其中创建的所有未引用的资源。

在您的情况下, aMassiveList永远不会离开上下文。 如果您希望您的function永远不会返回,您必须找到一种方法来“处理”您的信息并将其释放,而不是永久存储它们。

如果您创建的函数越来越多地分配资源并且永远不会释放它,那么最终会占用所有内存。

GC只会释放未引用的对象,因此当程序引用字典时,GC无法释放它

你编写WasteMemory方法的方式,它永远不会退出(除非变量“i”溢出,今年不会发生)并且因为它永远不会退出它将保持IN USE对内部Dictionary的引用。

Daniel White是对的,您应该阅读GC的工作原理。

如果引用正在使用中,GC将不会收集引用的内存。 否则,任何程序将如何工作?

我没看到你期望CLR / GC在这里做什么。 在您的WasteMemory方法的一次运行中没有任何垃圾收集。

然而,更令人困惑的是,如果我们等到任务完成,然后再次按Enter键再次运行任务,内存被释放,所以很明显以前的字典已经被垃圾收集了(不是吗?)。

按Enter键时,将创建并启动新任务。 这不是同一个任务 ,它是一个新任务 – 一个新对象,包含对新的WasteOfMemory实例的引用。

旧任务将继续运行,并且不会收集它使用的内存,因为旧任务一直在后台运行并且它继续使用该内存。

我不确定为什么 – 最重要的是如何 – 你观察到正在发布的旧任务的记忆。

将您的方法更改为using语句

例:

 Using (WateOfMemory memory = new WateOfMemory()) { Task tast = new Task(memory.WasteMemory); tast.Start(); } 

并添加可处置的WateOfMemoryClass(顺便提一下你的构造函数是WasteOfMemory)

上述就是C#学习教程:任务完成后C#不释放内存分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

 #region Dispose private IntPtr handle; private Component component = new Component(); private bool disposed = false; public WateOfMemory() { } public WateOfMemory(IntPtr handle) { this.handle = handle; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if(!this.disposed) { if(disposing) { component.Dispose(); } CloseHandle(handle); handle = IntPtr.Zero; } disposed = true; } [System.Runtime.InteropServices.DllImport("Kernel32")] private extern static Boolean CloseHandle(IntPtr handle); ~WateOfMemory() { Dispose(false); } #endregion 

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1014987.html

(0)
上一篇 2021年12月30日
下一篇 2021年12月30日

精彩推荐