【转】.net框架读书笔记---CLR内存管理\垃圾收集(三)
接上一篇.net框架讀書筆記---CLR內存管理\垃圾收集(二),主要學習了終止化對象(實現了Finalize方法的對象),了解了終止化對象的弊端,學習了通過實現IDisposable接口,通過Dispose方法來清理非托管資源,從而減輕垃圾收集器的壓力,本節繼續學習。
一、使用實現了Dispose模式的類型
System.IO.FileStream其基類Stream實現了IDisposable接口:
class?Program
{
static?void?Main(?string?[] args)
{
//?創建要寫入臨時文件的字節
byte?[] b?=?new?byte?[] {?1?,?2?,?3?,?4?,?5?};
FileStream fs?=?new?FileStream(?"?temp.dat?"?, FileMode.Create);
//?寫入臨時文件
fs.Write(b,?0?, b.Length);
fs.Close();
//?fs.Write(b, 0, b.Length);?//?該行會爆出異常,試圖寫入關閉的文件
File.Delete(?"?temp.dat?"?);
}
}
?
上面的代碼如果File.Delete之前不調用close是會報錯的,delete之前必須保證文件已經關閉。注意調用CLose方法后FileStream對象仍然在托管堆中,最后垃圾收集器會運行,并將該FileStream對象判定為可收集的垃圾。這時垃圾收集器本來應該調用FileStream對象上的Finalize方法,但是因為Dispose方法調用了GC的SuppressFinalize方法,所以Finalize方法不再被調用,對象的內存直接被回收。
二、C#的using語句
上面的例子應該使用try/catch塊中如下:
class?Program
{
static?void?Main(?string?[] args)
{
//?創建要寫入臨時文件的字節
byte?[] b?=?new?byte?[] {?1?,?2?,?3?,?4?,?5?};
FileStream fs?=?new?FileStream(?"?temp.dat?"?, FileMode.Create);
try
{
//?寫入臨時文件
fs.Write(b,?0?, b.Length);
}
catch
{
//?do someting
}
finally
{
fs.Close();
}
//?fs.Write(b, 0, b.Length);?//?該行會爆出異常,試圖寫入關閉的文件
File.Delete(?"?temp.dat?"?);
}
}
對于上述代碼C#提供了更為簡潔的語法,可以使用using語句
class?Program
{
static?void?Main(?string?[] args)
{
//?創建要寫入臨時文件的字節
byte?[] b?=?new?byte?[] {?1?,?2?,?3?,?4?,?5?};
using?(FileStream fs?=?new?FileStream(?"?temp.dat?"?, FileMode.Create))
{
//?寫入臨時文件
fs.Write(b,?0?, b.Length);
}
//?fs.Write(b, 0, b.Length);?//?該行會爆出異常,試圖寫入關閉的文件
File.Delete(?"?temp.dat?"?);
}
}
首先在using語句內初始化一個對象,并將其引用保存在一個變量內。然后在using大括號內訪問該變量。當編譯這段代碼,編譯器會自動創建一個try和finalily塊。在finally內編譯器會調用其Dispose方法,顯然,using語句只能用于那些實現了IDisposable接口的類型。
上面代碼的IL為
.method?private?hidebysig?static?void?Main(?string?[] args) cil managed
{
.entrypoint
//?代碼大小 76 (0x4c)
.maxstack?4
.locals init ([?0?] uint8[] b,
[?1?]?class?[mscorlib]System.IO.FileStream fs,
[?2?]?bool?CS$?4?$?0000?)
IL_0000: nop
IL_0001: ldc.i4.?5
IL_0002: newarr [mscorlib]System.Byte
IL_0007: dup
IL_0008: ldtoken field valuetype?'?<PrivateImplementationDetails>{7FD0DAA5-56D7-474F-B21D-5AECDF07BAFB}?'?/?'?__StaticArrayInitTypeSize=5?'?'?<PrivateImplementationDetails>{7FD0DAA5-56D7-474F-B21D-5AECDF07BAFB}?'?::?'?$$method0x6000001-1?'
IL_000d: call?void?[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(?class?[mscorlib]System.Array,
valuetype [mscorlib]System.RuntimeFieldHandle)
IL_0012: stloc.?0
IL_0013: ldstr?"?temp.dat?"
IL_0018: ldc.i4.?2
IL_0019: newobj instance?void?[mscorlib]System.IO.FileStream::.ctor(?string?,
valuetype [mscorlib]System.IO.FileMode)
IL_001e: stloc.?1
.?try
{
IL_001f: nop
IL_0020: ldloc.?1
IL_0021: ldloc.?0
IL_0022: ldc.i4.?0
IL_0023: ldloc.?0
IL_0024: ldlen
IL_0025: conv.i4
IL_0026: callvirt instance?void?[mscorlib]System.IO.Stream::Write(uint8[],
int32,
int32)
IL_002b: nop
IL_002c: nop
IL_002d: leave.s IL_003f
}?//?end .try
finally
{
IL_002f: ldloc.?1
IL_0030: ldnull
IL_0031: ceq
IL_0033: stloc.?2
IL_0034: ldloc.?2
IL_0035: brtrue.s IL_003e
IL_0037: ldloc.?1
IL_0038: callvirt instance?void?[mscorlib]System.IDisposable::Dispose()
IL_003d: nop
IL_003e: endfinally
}?//?end handler
IL_003f: nop
IL_0040: ldstr?"?temp.dat?"
IL_0045: call?void?[mscorlib]System.IO.File::Delete(?string?)
IL_004a: nop
IL_004b: ret
}?//?end of method Program::Main
很明顯可以看到try/finally,剛才試了一下,using不能處理異常的,看上面的IL會發現,其沒有catch,感覺很不爽。using也不能濫用,避免過早的調用了dispose。導致應用程序產生異常(ObjectDisposeException)
總結
以上是生活随笔為你收集整理的【转】.net框架读书笔记---CLR内存管理\垃圾收集(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】WPF入门教程系列六——布局介绍与
- 下一篇: 19包!男子扛1200斤硬币买比亚迪汽车