在C#中,调用Dispose方法是否会从堆中删除对象?

5
如果我执行conn.Dispose()方法(其中conn是SqlConnection类的一个实例),那么它会清除堆中的conn对象吗?
6个回答

13
不,调用Dispose方法不会清除连接在堆上的内容。当你在SqlConnection实例上调用Dispose方法时,你所做的只是将连接返回到底层连接池中。它甚至不会关闭连接。ADO.NET使用连接池。因此,当你创建一个新的SqlConnection实例时,你并没有打开一个新的连接,而是从连接池中获取一个连接,当你调用Dispose方法时,只是将这个连接返回给连接池,以便它可以被重复使用。
通常,在.NET中,IDisposable模式旨在由持有某些指向未托管资源的指针的类实现。调用Dispose方法确保这些未托管资源将被正确释放。
从堆中删除对象是垃圾回收器的工作,这是一个非确定性事件(你无法控制)。

请您能详细说明一下吗? - BlackBear
那么它是做什么的?我如何将它(conn)从堆中删除? - developer747
1
@ken2k,不,调用Dispose不会关闭底层连接。它只是将此连接返回到ADO.NET连接池中。 - Darin Dimitrov
2
@ken2k,你有没有看到文档中的第二个“注意事项”:当从连接池中获取或返回连接时,服务器不会触发登录和注销事件,因为连接在返回到连接池时并没有真正关闭。更多信息请参见SQL Server连接池(ADO.NET)。 - Darin Dimitrov
1
@asawyer,您不需要显式地执行它。当您编写using (SqlConnection myConn = new .....)时,实际上是调用Dispose方法。 - ken2k
显示剩余14条评论

1

不行。请参见msdn。 对象仍然存在,直到所有引用都消失。 以下是一个小例子:

myObject = new Something();
myObject.Dispose()
myObject.Foo() // still perfectly valid (but pretty ugly)
myObject = null; // now the reference, while still living, could be collected.
GC.Collect(); // now it is quite sure gone. (never call it unless you have good reasons)

1
不可以,这是垃圾回收器的工作。你无法直接与堆进行交互。
调用 Dispose() 可以确定性地关闭昂贵的资源(在本例中为网络连接)。

1

来自 MSDN:IDisposable.Dispose

使用此方法关闭或释放由实现此接口的类的实例持有的未托管资源,例如文件、流和句柄。

因此,Dispose 是关于垃圾回收器视图之外的底层资源。Dispose 不是关于实例本身。


这会清除堆中的conn对象吗?
SqlConnection实例将释放其未托管的连接资源(通过将其返回到连接池)。 SqlConnection实例不会从内存中“Dispose”自己 - 它是托管对象,垃圾回收器负责该工作。

David,当垃圾回收器调用析构函数时,是否会自动调用实现IDisposable接口的类的Dispose()方法? - developer747
不,终结器不会自动调用Dispose。编写终结器来调用Dispose也被认为是不好的做法,因为您无法控制GC何时调用该终结器。最佳实践是使用Using语句确保调用Dispose。 - Amy B

1
IDisposable的目的是提供一种标准方式通知对象它们不再需要了。有些对象要求其他实体(这些实体可能甚至不在同一台计算机上!)代表它们执行某些操作,直到另行通知为止。当一个对象被告知它不再需要时,它可以通知任何可能代表它执行操作的实体,让它们不再需要这么做。
作为一个简单的例子,创建一个文件对象可能会(间接地)导致向文件服务器发出请求,以独占模式打开特定的文件。在文件服务器收到关闭文件的请求之前,它将不允许已知宇宙中的任何其他人访问该文件。只要文件对象还需要,它就会保持对文件的独占访问权限。如果在文件对象上调用IDisposable.Dispose,则会(再次间接地)导致发送一个“关闭”请求到文件服务器,从而允许其他程序和计算机访问该文件。
请注意,如果文件对象不通知任何人先前授予的独占文件访问权已不再需要,它将简单地消失,服务器可能永远不会让其他人使用该文件。为了防止这种问题发生,文件对象的类可以定义Finalize()处理程序。每当系统创建一个覆盖Object.Finalize()的类的对象时,系统都会将其添加到具有“已注册”Finalize处理程序的特殊对象列表中。如果这样的对象被遗弃,垃圾收集器将在实际从内存中删除它或它直接或间接引用的任何对象之前运行其Finalize方法。
请注意,Dispose的目的不是销毁文件对象本身,而是允许它通知提供独占访问文件的实体不再需要这样的访问权限。对覆盖Object.Finalize()的类的对象调用Dispose将通知垃圾收集器不再需要担心在将对象从内存中删除之前调用Finalize方法,但不会销毁对象。

1

不。

IDisposable 为“处理”对象提供了一个众所周知的接口。处理通常是为了显式释放资源,否则这些资源将一直保留,直到对象超出范围并被垃圾回收,即当对象从内存中移除时(几乎总是堆内存)。

略微偏题,您还应该知道 using 关键字与 IDisposable 一起使用。

using (var disposableObject = new DisposableObject())
{
   ..do stuff with disposableObject..
} //disposableObject.Dispose() implicitly called here.

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