打破砂锅问到底,Close()和Dispose()的深入理解

zcxverygood123456 2010-09-19 12:27:26
网上查看了很多资料,有几个疑惑:
前提:
Close 是停业整顿,停业了,可以通过公关,再重开,物还是原来的物;只是关闭而已,没有释放真正的释放资源,可以重新打开;
Dispose 是炸毁,炸毁了,想再开张,就只有重头建起;是把对象销毁,将不再存在;

问题1、什么地方会这么用?比如新闻的显示页,我是用DataReader这个SqlConnection 先Open(),然后再Close();
这个地方到底我是用Close还是Dispose;还是两个一起用(先用Close再接着加Dispose)。

问题2、我打开了新闻的显示页后,可能第二天可能我还要打开,或者还有很多人也可能同时在看这条新闻,那么到底我是Close还是Dispose?我这里用Close有什么好处,要是用Dispose有什么用?是不是我Dispose炸毁了,第二天后我就不能打开这条新闻了?

问题3、实际一点(理论就不必多说了),哪些场合需要Close? 哪些场合需要Dispose?或者是哪些场合必须两者都要?
最好能举例子说明
...全文
443 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2011-07-22
  • 打赏
  • 举报
回复
ri.Close();riDispose();conn.Close();
「已注销」 2011-07-22
  • 打赏
  • 举报
回复
学习了...我感觉还是并用好点..
alian_1126 2010-09-26
  • 打赏
  • 举报
回复
mark~!!~!~!~
nageboy 2010-09-20
  • 打赏
  • 举报
回复
推荐一篇文章,希望你能顿悟

c# GC管理
凤凰涅檠 2010-09-20
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 dalmeeme 的回复:]

问题二:对每个浏览者分别创建不同的对象,即使Dispose也只是销毁了某个浏览者对应的数据连接对象,不会影响别人的。浏览者下次再浏览会重新实例化对象。

[/Quote]


这个我不是很明白,难道每个 客户端请求的是不同的 服务器端吗?每个浏览者都会有不同的对象,这句怎么理解
dengxiao1981 2010-09-20
  • 打赏
  • 举报
回复
学习...
zcxverygood123456 2010-09-20
  • 打赏
  • 举报
回复
总结下来,有几个问题没弄懂:
第一个问题:Close()方法只是关闭了连接,然后这个连接被存储到连接池,所以在调用Close()方法以后,还是可以再通过 Open()方法来打开连接的
======================
什么情况用到呢?
一般我是先Open()再Close()就完了,
没有过Open()再Close(),然后再Open()的情况,
比如打开新闻显示页,用DataReader这个SqlConnection 先Open(),然后再Close();就可以看新闻了,这个地方没必要把这个连接被存储到连接池,因为我没必要再通过 Open()方法来打开连接了。
所以不知这个“可以再通过 Open()方法来打开连接”有什么用?

第二个问题:打个比方说,你用浏览器上csdn首页,当把网页html流发送给浏览器后不久html流就关闭了,相当于Dr1.Close();当你把浏览器关闭或者跳到别的网站,那么网站连接也关闭了,相当于myCmd1.Connection.Close()。
============
那么这些关闭是否正在意义上的释放资源呢?

第三个问题:1、还有就是:WEB.config 里面:在数据库连接加 Max Pool Size = 512 这里的意思是不是最大连接数为512个,如果超过了,服务器怎么处理呢?
2、DataReader是独占连接的,比如说最大连接设100,假设有100个人同时使用DataReader正在读取数据库内容,那么当第101人读取的时候,连接池中的连接已经没有了,Connection对象的Close()方法,这是不行的,因为Close()方法仅仅是关闭连接,但这个连接没有释放,还是被这个对象占用,要释放必须使用Connection的Dispose()方法显式释放连接才可以,否则这个对象占用的连接只能等到垃圾收集的情况下才能被释放。这种情况肯定会出现“超时时间已到”的错误。
-----------
这是我在网上找到,这样的理解到底对不对?

第四个问题:Close是关闭数据连接,但DataReader对象还在
===================
那么对正在运行的网站有没有影响?
因为前几天我搞忘记了加Close(),恰巧这个页面有20多个DataReader,接连打开这个页面几次后,就出现“超时时间已到。在从池中获取连接之前超时时间已过。”,后来我加了Close()后就不会出现了。
但想优化再优化,是否也把Dispose()加进去是否能更好?

第五个问题:SqlCommand myCmd1 = new SqlCommand(mySel, myConn);
myCmd1.Connection.Open();
SqlDataReader Dr1 = myCmd1.ExecuteReader();
Dr1.Read();
string Count = Dr1["iCount"].ToString();
Dr1.Close();
myCmd1.Connection.Close();
==========================
以上代码:我通过ExecuteReader()该命令得出了结果Dr1["iCount"].ToString();
那么接下来程序用这个结果来判断做其它事情了,那么这个时候myCmd1.Connection.Close();取到什么作用?“只是关闭而已,没有释放真正的释放资源,可以重新打开;
”我已经得到我的结果了数据了,我还需要打开吗?
zcxverygood123456 2010-09-20
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 nageboy 的回复:]
推荐一篇文章,希望你能顿悟

c# GC管理
[/Quote]
===================
此页面打不开
dalmeeme 2010-09-19
  • 打赏
  • 举报
回复
不加Dispose()的话DataReader对象还会在服务器内存中存在,但只要创建对象的外层的方法体执行完毕,DataReader应该就释放了吧。如果方法体很大而数据操控在很前面,后面还有很多别的东西要执行,那就操控完后马上Dispose,否则我觉得也没必要。
zcxverygood123456 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 dalmeeme 的回复:]
打个比方说,你用浏览器上csdn首页,当把网页html流发送给浏览器后不久html流就关闭了,相当于Dr1.Close();当你把浏览器关闭或者跳到别的网站,那么网站连接也关闭了,相当于myCmd1.Connection.Close()。
[/Quote]
============
那么这些关闭是否正在意义上的释放资源呢?
神码浮云 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 zhangaijiang 的回复:]
很多人都认为Close()方法内部会调用Dispose()方法,所以并没有本质的区别!实际上这个看法不是很准确,对有些类来说,的确Close()和Dispose()没有本质区别,但是对有些类来说并非如此!
首先,让我们看看我们最常使用的SqlConnection的Close()方法和Dispose()方法的区别:
SqlConnection类的Dispose()方法是继承于Compon……
[/Quote]

很好, 学习学习 ..
zcxverygood123456 2010-09-19
  • 打赏
  • 举报
回复
1、还有就是:WEB.config 里面:在数据库连接加 Max Pool Size = 512 这里的意思是不是最大连接数为512个,如果超过了,服务器怎么处理呢?
2、DataReader是独占连接的,比如说最大连接设100,假设有100个人同时使用DataReader正在读取数据库内容,那么当第101人读取的时候,连接池中的连接已经没有了,Connection对象的Close()方法,这是不行的,因为Close()方法仅仅是关闭连接,但这个连接没有释放,还是被这个对象占用,要释放必须使用Connection的Dispose()方法显式释放连接才可以,否则这个对象占用的连接只能等到垃圾收集的情况下才能被释放。这种情况肯定会出现“超时时间已到”的错误。
-----------
这是我在网上找到,这样的理解到底对不对?
dalmeeme 2010-09-19
  • 打赏
  • 举报
回复
打个比方说,你用浏览器上csdn首页,当把网页html流发送给浏览器后不久html流就关闭了,相当于Dr1.Close();当你把浏览器关闭或者跳到别的网站,那么网站连接也关闭了,相当于myCmd1.Connection.Close()。
zcxverygood123456 2010-09-19
  • 打赏
  • 举报
回复
dalmeeme(无机战士)

Close是关闭数据连接,但DataReader对象还在
===================
那么对正在运行的网站有没有影响?
因为前几天我搞忘记了加Close(),恰巧这个页面有20多个DataReader,接连打开这个页面几次后,就出现“超时时间已到。在从池中获取连接之前超时时间已过。”,后来我加了Close()后就不会出现了。
但想优化再优化,是否也把Dispose()加进去是否能更好?
zcxverygood123456 2010-09-19
  • 打赏
  • 举报
回复
比如:
SqlCommand myCmd1 = new SqlCommand(mySel, myConn);
myCmd1.Connection.Open();
SqlDataReader Dr1 = myCmd1.ExecuteReader();
Dr1.Read();
string Count = Dr1["iCount"].ToString();
Dr1.Close();
myCmd1.Connection.Close();
==========================
以上代码:我通过ExecuteReader()该命令得出了结果Dr1["iCount"].ToString();
那么接下来程序用这个结果来判断做其它事情了,那么这个时候myCmd1.Connection.Close();取到什么作用?“只是关闭而已,没有释放真正的释放资源,可以重新打开;
”我已经得到我的结果了数据了,我还需要打开吗?
===============
说明一下:以上代码的意思是在登录的时候,先判断用户名是否存在,即如果Count==“0”的就不存在的意思。
我这时候已经得到string Count 数据了,如果我用Dispose炸毁了,第二天后我就不能再用了。
或是我理解错了。
dalmeeme 2010-09-19
  • 打赏
  • 举报
回复
问题一:Close是关闭数据连接,但DataReader对象还在,可能要过较长时间才会被垃圾回收。Dispose是要求马上回收。
问题二:对每个浏览者分别创建不同的对象,即使Dispose也只是销毁了某个浏览者对应的数据连接对象,不会影响别人的。浏览者下次再浏览会重新实例化对象。
问题三:Close是必须用的,Dispose可用可不用,如果负荷流量大就用Dispose。
zhangaijiang 2010-09-19
  • 打赏
  • 举报
回复
很多人都认为Close()方法内部会调用Dispose()方法,所以并没有本质的区别!实际上这个看法不是很准确,对有些类来说,的确Close()和Dispose()没有本质区别,但是对有些类来说并非如此!
首先,让我们看看我们最常使用的SqlConnection的Close()方法和Dispose()方法的区别:
SqlConnection类的Dispose()方法是继承于Component类的,源代码是这样的:
public void Dispose() {
Dispose(true); //调用Dispose的一个带参数的重载
GC.SuppressFinalize(this); //请求系统不要调用指定对象的终结器。
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
lock(this) {
if (site != null && site.Container != null) {
site.Container.Remove(this);
}
if (events != null) {
EventHandler handler = (EventHandler)events[EventDisposed];
if (handler != null) handler(this, EventArgs.Empty);
}
}
}
}
SqlConnection类的Close()方法在MSDN中的说明是这样的:
关闭与数据库的连接。这是关闭任何打开连接的首选方法。 如果 SqlConnection 超出范围,则不会将其关闭。因此,必须通过调用 Close 或 Dispose 显式关闭该连接。Close 和 Dispose 在功能上等效。如果连接池值Pooling 设置为 true 或 yes,则基础连接将返回到连接池。另一方面,如果 Pooling 设置为 false 或 no,则会关闭到服务器的基础连接。
看说明好象是Close()方法和Dispose()方法是类似的,实际上只是在关闭连接这个功能上等效,让我们看看Close ()方法的源代码:
override public void Close() {
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.SqlConnection.Close|API> %d#" , ObjectID);
try {
SqlStatistics statistics = null;

RuntimeHelpers.PrepareConstrainedRegions();
try {
#if DEBUG
object initialReliabilitySlotValue = Thread.GetData(TdsParser.ReliabilitySlot);

RuntimeHelpers.PrepareConstrainedRegions();
try {
Thread.SetData(TdsParser.ReliabilitySlot, true);
#endif //DEBUG
statistics = SqlStatistics.StartTimer(Statistics);

// The lock here is to protect against the command.cancel / connection.close

race condition
// The SqlInternalConnectionTds is set to OpenBusy during close, once this

happens the cast below will fail and
// the command will no longer be cancelable. It might be desirable to be

able to cancel the close opperation, but this is
// outside of the scope of Whidbey RTM. See (SqlCommand::Cancel) for other

lock.
lock (InnerConnection) {
InnerConnection.CloseConnection(this, ConnectionFactory);
}
// does not require GC.KeepAlive(this) because of OnStateChange

if (null != Statistics) {
ADP.TimerCurrent(out _statistics._closeTimestamp);
}
#if DEBUG
}
finally {
Thread.SetData(TdsParser.ReliabilitySlot, initialReliabilitySlotValue);
}
#endif //DEBUG
}
catch (System.OutOfMemoryException e) {
Abort(e);
throw;
}
catch (System.StackOverflowException e) {
Abort(e);
throw;
}
catch (System.Threading.ThreadAbortException e) {
Abort(e);
throw;
}
finally {
SqlStatistics.StopTimer(statistics);
}
}
finally {
SqlDebugContext sdc = _sdc;
_sdc = null;
Bid.ScopeLeave(ref hscp);
if (sdc != null) {
sdc.Dispose();
}
}
}
可以看到Close()方法并没有调用Dispose()方法,虽然有一行sdc.Dispose();,但是这只是释放SqlDebugContext

实例,和SqlConnection.Dispose()方法没有关系!

那么区别在哪里呢?
Close()方法只是关闭了连接,然后这个连接被存储到连接池,所以在调用Close()方法以后,还是可以再通过 Open()方法来打开连接的而调用Dispose()方法以后,这个连接就不能在使用了!
还有一个重要区别就是,当Close()方法并没有调用GC.SuppressFinalize(this);,这导致的直接后果就是在垃圾回收的时候需要进行终止化操作,这会导致这个实例的“代龄”提升,从而极大的延迟这个对象的回收时间!
针对SqlConnection这个类来说,如果以后还需要使用这个连接可以使用Close()方法临时关闭连接,如果以后不需要使用这个连接了,可以优先选用Dispose()方法来释放资源,当然你可以使用using关键字来简化这个过程,
OleDbConnection类和OdbcConnection类的源代码我没有找到,但是应该和SqlConnection类是类似的!
让我们在看一个我们常用的类,看看FileStream类的Close()方法和Dispose()方法有什么区别:
FileStream类的Close()方法是继承于Stream类的,源代码是这样的:
public virtual void Close()
{
Dispose(true);
GC.SuppressFinalize(this);
}
FileStream类的Dispose()方法是继承于Stream类的,源代码是这样的:
public void Dispose()
{
Close();
}
是一个标准的Dispose模式的实现,Close()方法调用的是带参数的Dispose方法,然后调用GC.SuppressFinalize(this);请求系统不要调用指定对象的终结器。而Dispose()方法直接调用Close()方法!
对于FileStream类来说,Close()方法和Dispose()方法是没有区别!
MSDNXGH 2010-09-19
  • 打赏
  • 举报
回复
比如,con.close();con.disponse();
MSDNXGH 2010-09-19
  • 打赏
  • 举报
回复
安全起见。。可以两者一起用,
村长_乐 2010-09-19
  • 打赏
  • 举报
回复
学习...
加载更多回复(1)

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧