我自己和一位同事在.NET中垃圾收集對象時有不同的看法。看看下面的代碼:.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
對象是調用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();
}
然後request
不能被垃圾調用request.Stream
後收集它仍然是來自finally
塊到達。
另外,如果垃圾回收器有可能收集對象,則finally
塊可能會顯示未定義的行爲,因爲Dispose
將在GC對象上調用,這是沒有意義的。同樣,也無法優化掉finally
塊作爲異常可以在try
/using
塊任何垃圾回收已經發生之前,這將需要finally
塊執行中被拋出。
忽略終結器中關閉流的問題是否有可能垃圾收集器在finally
塊的末尾之前收集對象,實際上優化finally
塊中的邏輯?
你是對的,直到finally運行,請求才能被GCed。 – 2014-12-05 12:55:17
請注意,如果request.Dispose沒有使用實例字段,請求*可以在對其調用Dispose之前收集。這是一種罕見的情況。 – usr 2014-12-05 12:58:06
建議:不要使用終結器。然後,這個問題就變得沒有意義了。您無法在工作中檢測到GC(除非通過非常不尋常的方式,例如終結器或調試API)。爲什麼Request.Finalize需要關閉流?流本身有一個終結器。 – usr 2014-12-05 12:59:11