未正确实现IDisposable的后果

时间:2011-01-05 16:55:55

标签: c# .net idisposable

我很熟悉如何实现IDisposable ..

但是我不清楚没有正确实施这一点的确切后果。这种情况是非托管资源永远不会被清除从而导致内存泄漏,或者内存最终是否会被回收,而不是及时回收?

7 个答案:

答案 0 :(得分:12)

取决于。

如果有问题的对象无法实现IDisposable,但仍然正确实现终结器,那么资源最终将被清除。

但是,如果它没有正确实现终结器,并且它正在包装非托管资源,那么该资源将被泄露。这通常是资源泄漏(即:泄漏存储为IntPtr的HANDLE)比传统的“内存泄漏”更多(当然,指向的对象仍然使用内存)。

  

记忆最终会被回收吗?

这里有一点...... IDisposable与内存无关 - 它与资源有关。这些资源通常使用自己的内存,但实现IDisposable不会导致垃圾收集器更快地回收内存。

答案 1 :(得分:4)

当然,这完全取决于实施方式。

SqlTransaction上的错误处置可能会导致过长的阻塞,例如 - 影响多台计算机和用户。 SqlConnection上的错误处置可能导致连接饱和并且无法连接。这些不仅仅是内存(等)问题。

IIRC一个丢失的图形(笔/画笔/无论如何)处理导致VS崩溃错误 - 由于没有内存压力,GC没有发生,所以相反它只是使GDI处理并破坏了。

不正确的文件/流配置可能会导致异常,因为文件无法读取/写入 - 可能会丢失数据。

如果没有妥善处理非托管资源,一切皆有可能。

答案 2 :(得分:2)

不要考虑一些模糊定义的“资源”,而是将IDisposable视为“这个对象以一种需要清理的方式操纵自身之外的东西(甚至可能在计算机之外!)”这种清理所需的信息仍然存在。“起火的终结者基本上说“没有其他人正在使用这些东西了,我是唯一知道它的人;我最好清理它,因为没有其他人会这样做。”

假设终结者会神奇地处理事情是危险的;虽然许多物体可以安全地放弃,但许多其他物体却不能。在某些情况下,对象很容易检测到它已被放弃并适当地清理。在其他一些情况下,可能难以实现。考虑一个对象,该对象应该计算“quack”这个词出现在长期数据流中的次数。如果对象的创建者忘记了它,并且没有人会查询计数,那么该对象也可能会消失。不幸的是,由于数据流保存对计数对象的引用(以便在数据进入时让它知道),因此计数器对象不会消失。如果代码创建一个计数器,然后忘记它,然后创建另一个,忘记它,等等。这可能会成为一个无限制的内存泄漏。

答案 3 :(得分:1)

保存非托管资源的类应确保在最终确定期间清除它们。但是,这只发生在垃圾收集器到达它时。

不调用Dispose意味着在资源释放之前等待垃圾收集器需要内存。

答案 4 :(得分:0)

两者中的后者。只是没有及时。

这一点的重要性取决于您分配的资源。这就是为什么你更有可能在打开文件的对象上看到IDisposable接口,并引用其他更多的crticital资源。

答案 5 :(得分:0)

是的,永远不会释放非托管资源。 (这假设有问题的IDisposable类型没有实现“后备”终结者。如果他们这样做,那么终结者应该最终解决问题......最终。)

然而,您需要担心的不仅是非托管内存分配;这是任何非托管资源。例如,如果您没有正确处理数据库连接,那么您可能会发现连接池很快就会耗尽。

答案 6 :(得分:0)

另一个潜在的问题是没有正确实施一次性模式 - 很容易意外地调用.Dispose()不止一次。如果您的Dispose方法没有检查对它的连续调用,并且(例如)尝试多次释放非托管资源,则可能会出现一些不可恢复的错误或意外行为。