C#中的内存处理顺序和GC

时间:2010-11-15 16:01:40

标签: c# garbage-collection dispose

在C#中实际发生的事情:

1) A method gets invoked.
2) The method allocates memory (e.g. MemoryStream mm = new MemoryStream()).
3) An exception occurs in the method which is caught by the invoking classes.

垃圾收集器是否释放了资源“mm”?这是安全风险(例如DoS)吗?

P.S。:我知道最好的做法是明确地释放任何已分配的资源。这意味着使用“using”-statement或“try / catch / finally”-block。

4 个答案:

答案 0 :(得分:11)

  

垃圾收集器是否释放了资源“mm”?

一旦死了,是的。最终GC将运行并释放内存(如果它未被引用)。

  

这是安全隐患吗?

让我们的术语准确无误。 资产是有价值的东西:私人数据,用户的时间等等。 攻击者是指希望对资产造成伤害的人。 威胁是攻击者可能造成伤害的方式。 漏洞是该方案的一个方面,攻击者可以利用该方案来弥补威胁。

要回答您的问题,我们需要知道:

  • 什么是资产?
  • 谁是攻击者?
  • 攻击者对资产构成的威胁是什么?
  • 攻击者利用哪些漏洞来弥补威胁?

只有在您说明这些问题的答案后,我们才能知道在异常时是否立即释放内存缓冲区是一种安全隐患。

对于一个真实的例子,资产可能是我的电视,攻击者可能是小偷,威胁是盗窃,漏洞是一个解锁的二楼窗户和我车库里的梯子。梯子和窗户都是这种威胁的脆弱性的一部分。然而,它们都不容易受到纵火的威胁。在了解现实威胁之前,您无法确定某种情况的风险!

  

我知道最佳做法是明确释放任何已分配的资源。

最好明确清理非托管资源,例如由操作系统控制的文件句柄。通常,您让垃圾收集器清理托管内存。

答案 1 :(得分:5)

垃圾收集器不会删除分配给mm的内存,直到1)垃圾收集器运行,2)mm创建的引用被标记为垃圾收集,3)引用是最终确定。

即使在异常情况下,为mm创建的内存仍然可以保留,特别是如果某个其他对象引用了mm

现在......那是一个安全漏洞吗?取决于情况。是的,完全有可能为DoS分配太多内存;这是任何系统的问题,但坦率地说很少需要处理,除非你的代码对于悬空记忆特别糟糕。有时,您可能希望使用ValueType struct作为暂时值;这一切都取决于具体情况,没有一种正确的做法。

关于你的PS:在.NET中,明确释放每个分配的资源并不是最佳做法;明确释放非托管资源的最佳做法。最佳做法是让管理资源位于,除非您发现性能问题,此时您可以考虑更严格的内存管理方法。让GC正常工作,在100个案例中的99个案例中,一切都会好起来的。

了解更多信息:

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

答案 2 :(得分:1)

你应该使用thr try / catch / finally结构并将mm.Disponse()调用到tye finally块以释放所有非托管资源。在memoryStream的情况下,它调用Stream.Dispose(),然后它将处理创建的事件 作为调用异步方法的结果(.BeginRead(),. BeginWrite()) 如果他们都没有在流完成之前完成

答案 3 :(得分:1)

我只是想补充一下使用声明的一些说明。

任何处理非托管资源的对象(例如文件和字体)都应该实现IDisposable接口......这是Using statement的工作原理。

IDisposable和Using语句的目的是确保非托管资源得到正确清理,而不是在完成后留下闲置资源。

所以,是的,最佳实践是实现Using语句;但是,最好的做法是释放“任何”分配的资源,而不是非托管资源。

每个MS:通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它。