.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)