Sea*_*ean 8 .net c# garbage-collection memory-management
我自己和同事对于什么时候可以在.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);
}
Run Code Online (Sandbox Code Playgroud)
我的同事声称,当使用服务器垃圾收集器运行发布版本时request,在调用之后对该对象进行垃圾收集是有效的request.Stream.他断言这只发生在服务器垃圾收集器上,而不是工作站垃圾收集器.
这是因为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();
}
Run Code Online (Sandbox Code Playgroud)
然后request在调用之后无法进行垃圾收集request.Stream仍然可以从finally块中获取.
此外,如果垃圾收集器可能收集对象,那么该finally块可能会显示未定义的行为,就像Dispose在GC对象上调用一样,这是没有意义的.同样地,不可能优化掉finally块,因为在发生任何垃圾收集之前可能会在try/ using块内抛出异常,这将需要finally块执行.
忽略在终结器中关闭流的问题,垃圾收集器是否有可能在finally块结束之前收集对象,并实际上优化了finally块中的逻辑?
Sam*_*ell 10
这个问题有很多,所以我将首先解决这些首要问题.
声明中using声明的变量在块结束之前不会被垃圾收集,这正是您指示的原因 - 为了调用Dispose()隐式finally块而保持引用.
如果你发现自己在C#中编写终结器,那么你可能做错了什么.如果你在C#调用终结器Stream.Dispose(),你肯定做错了什么.除了.NET本身的实现之外,我已经看到了数百个误用的终结器,并且确实需要1个终结器.有关更多信息,请参阅DG更新:Dispose,Finalization和Resource Management.
ObjectDisposedException与最终确定无关.此异常通常在代码调用Dispose()对象(而不是finalize)时发生,然后稍后调用以对该对象执行某些操作.
有时代码处理时并不明显Stream.令我感到惊讶的一个案例是使用StreamContent发送HTTP请求的一部分HttpClient.该实现调用Stream.Dispose()发送请求后,所以我不得不写一个包装Stream类称为DelegatingStream从转换过程中保护我们图书馆原来的行为HttpWebRequest来HttpClient.
您可以看到的一种情况ObjectDisposedException是,该getStream()方法是否缓存Stream实例并将其返回以用于将来的多个调用.如果Request.Dispose()丢弃了流,或者DoStuff2(Stream)处理了流,那么下次尝试使用流时,您将得到一个流ObjectDisposedException.
根据语言规范,第3.9节:"如果对象或其任何部分无法通过任何可能的继续执行来访问,除了运行析构函数之外,该对象被认为不再使用,并且它符合条件破坏".在块(第8.13节)中using引入了一个Dispose调用finally,它不是运行析构函数,并且必须执行,除非在偶数finally块不执行的情况下(规范未涵盖,并且通常仅在整个AppDomain时发生)无论如何都要去墓地.)
using块中的对象不符合GC的条件.在您的示例中,request直到using声明之后才有资格进行销毁,无论是否在块的其余部分中使用它.唯一的极端情况(如其他人的评论中所述)是指您的Dispose实现不使用其this参数.在这种情况下,Dispose不会阻止对象符合销毁条件 - 但如果发生这种情况,那么何时可以收集它的问题是没有意义的(因为它应该是 - 垃圾收集,如果正确实施,应该没有可观察的对正确实施的程序的影响).
| 归档时间: |
|
| 查看次数: |
1058 次 |
| 最近记录: |