在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。
答案 0 :(得分:11)
垃圾收集器是否释放了资源“mm”?
一旦死了,是的。最终GC将运行并释放内存(如果它未被引用)。
这是安全隐患吗?
让我们的术语准确无误。 资产是有价值的东西:私人数据,用户的时间等等。 攻击者是指希望对资产造成伤害的人。 威胁是攻击者可能造成伤害的方式。 漏洞是该方案的一个方面,攻击者可以利用该方案来弥补威胁。
要回答您的问题,我们需要知道:
只有在您说明这些问题的答案后,我们才能知道在异常时是否立即释放内存缓冲区是一种安全隐患。
对于一个真实的例子,资产可能是我的电视,攻击者可能是小偷,威胁是盗窃,漏洞是一个解锁的二楼窗户和我车库里的梯子。梯子和窗户都是这种威胁的脆弱性的一部分。然而,它们都不容易受到纵火的威胁。在了解现实威胁之前,您无法确定某种情况的风险!
我知道最佳做法是明确释放任何已分配的资源。
最好明确清理非托管资源,例如由操作系统控制的文件句柄。通常,您让垃圾收集器清理托管内存。
答案 1 :(得分:5)
垃圾收集器不会删除分配给mm
的内存,直到1)垃圾收集器运行,2)mm
创建的引用被标记为垃圾收集,3)引用是最终确定。
即使在异常情况下,为mm
创建的内存仍然可以保留,特别是如果某个其他对象引用了mm
。
现在......那是一个安全漏洞吗?取决于情况。是的,完全有可能为DoS分配太多内存;这是任何系统的问题,但坦率地说很少需要处理,除非你的代码对于悬空记忆特别糟糕。有时,您可能希望使用ValueType
struct
作为暂时值;这一切都取决于具体情况,没有一种正确的做法。
关于你的PS:在.NET中,明确释放每个分配的资源并不是最佳做法;明确释放非托管资源的最佳做法。最佳做法是让管理资源位于,除非您发现性能问题,此时您可以考虑更严格的内存管理方法。让GC正常工作,在100个案例中的99个案例中,一切都会好起来的。
了解更多信息:
答案 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语句中声明并实例化它。”