我和同事对于.NET中一个对象何时可以被垃圾回收存在分歧。看下面的代码:
Stream stream=getStream();
using(var request=new Request(stream))
{
Stream copy=request.Stream;
// From here on can "request" be garbage collected?
DoStuff1();
DoStuff2(copy);
}
我的同事声称,当使用服务器垃圾回收器运行发布构建时,调用
request.Stream
后,request
对象可以被垃圾回收。他断言,这只会发生在使用服务器垃圾回收器时,而永远不会发生在工作站垃圾回收器上。原因是
Request
类有一个终结器,该终结器正在关闭提供给该请求的Stream
。因此,当DoStuff2
使用该流进行操作时,它会得到一个“对象已释放”异常。由于终结器只能由垃圾回收器运行,我的同事说,在finally块结束之前,必须进行了垃圾回收,但在最后使用request
之后。然而,我认为由于上面的代码只是以下内容的缩写:
Stream stream=getStream();
Request request=null;
try
{
Stream copy=request.Stream;
// From here on can "request" be garbage collected?
DoStuff1();
DoStuff2(copy);
}
finally
{
if(request!=null)
request.Dispose();
}
那么,由于在finally
块中仍然可以访问request
对象,因此在调用request.Stream
后,request
将无法被垃圾回收。
另外,如果垃圾回收器能够收集该对象,则finally
块可能会表现出未定义的行为,因为会对已经被垃圾回收的对象调用Dispose
,这是没有意义的。同样地,不可能优化掉finally
块,因为在进行任何垃圾回收之前,try
/using
块中可能会抛出异常,这将需要执行finally
块。
忽略在终结器中关闭流的问题,是否有可能在finally
块结束之前垃圾回收器收集该对象,并实际上优化掉finally
块中的逻辑?
Dispose
方法正在执行一些操作! - Seanusing
/finally
块结束之前GCrequest
对象?ODE是由Request
对象中糟糕编码的终结器引起的,但我的观点是它不应该在using
块结束之前运行终结器,而且只有在Dispose
之后才能运行。 - Sean