调用Dispose方法会清除和压缩.Net中的内存吗?

4

我对于在.Net中Dispose和Finalize方法有一个想法,如下所述。这个理解正确吗?

Dispose:实现IDisposable接口并在Dispose()方法中移除未使用/未托管的代码。如果开发者需要立即删除资源,他们需要手动调用它,否则当GC被调用时会自动清理资源。

Finalize:当GC被调用时,它将释放未使用的托管代码,并且如果实现了IDisposable,则会调用Dispose()方法以释放未管理的资源(通常情况下)。

基本上,当我们使用Dispose()方法释放资源时,内存会立即被释放和压缩(就像GC一样)吗?

3个回答

5
你的问题的答案是否定的:释放对象分配的内存与调用Dispose方法无关,当垃圾收集器到达时会自动释放。
一般来说,Dispose旨在加速释放外部资源,例如文件句柄、信号量、数据库句柄和其他通常由操作系统分配的项目。如果你的对象持有其他IDisposable对象,则应在其调用dispose时对它们进行处理。
然而,Finalizer是不同的:它作为垃圾收集的一部分被调用,并且旨在释放在dispose期间未被释放的外部资源(可能是因为用户忘记调用Dispose)。Finalizers不能调用你的对象可能持有的其他对象的Dispose,因为它们正在被垃圾收集。

当系统确定需要在对象上运行终结器时,它和所有其他它所持有引用的对象将被临时复活,并且在终结器运行之前不能进行垃圾回收。当一个对象的终结器运行时,它持有引用的任何其他对象可能已经(1)运行了它们的终结器;(2)已经安排好运行它们的终结器;或者(3)正在被其他东西使用。在这些情况下,不应该对其他对象运行Dispose,但这并不意味着其他对象正在“被GC”。 - supercat
@supercat,这就是为什么我没有说“已经被垃圾回收了”的原因 - 我的意思是这些依赖项在垃圾回收管道中的某个位置,甚至可能已经被终结;调用Dispose会导致问题(我不幸的是以一种艰难的方式学到了这一点)。 - Sergey Kalinichenko
我认为终结(finalization)和垃圾回收是不同的,因为已经被垃圾回收的对象不存在了。如果将唯一存在的对象引用从GC中隐藏起来(例如通过使用不安全代码将其转换为int,然后再将其转换回对象引用),尝试访问重构的对象引用将相当于在C中的野指针引用。相比之下,由正在进行终结的对象持有的任何对象引用都将引用到仍然存在的对象,就 .net GC而言。 - supercat

2

不对。直接调用Dispose方法或使用using语句并不会释放内存。

实现IDisposable只是为您的类提供清理其持有的任何非托管资源的机会。


1
最终化:当GC被调用时,它将释放未使用的托管代码,并且如果实现了IDisposable,则会调用Dispose方法以释放未管理的资源(通常情况下)。
您在这里有些不正确。当您说“它会调用Dispose”时,如果您指的是GC本身,那么不,它不会“自动”为您调用Dispose。作为程序员,在Dispose和Finalizer方法中进行清理是您的工作。
MSDN writeup here演示了典型的处理模式。
问题是:当我们使用Dispose方法释放资源时,内存会立即释放并压缩(就像GC一样)吗?
不,调用Dispose不会释放堆内存。堆内存直到GC运行并执行清理操作后才会被释放。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接