垃圾收集器哪些对象不清理?

Kev*_*ith 5 c# garbage-collection

静态分析工具不断告诉我,我的C#代码中有资源泄漏.

这是一个例子:

StringReader reader = new StringReader(...); 

// do something with reader

...

} // static analysis tool cries that I've leaked **reader**
Run Code Online (Sandbox Code Playgroud)

我的工具是否正确?如果是这样,为什么?

编辑(回复评论) - 我的静态分析工具说我有一堆资源泄漏.我从这个论坛知道需要显式释放某些Java AWT对象,否则会发生泄漏.是否需要明确释放C#对象?

Dar*_*rov 13

是的,你的代码泄漏严重.它应该是这样的:

using (StringReader reader = new StringReader(...))
{

}
Run Code Online (Sandbox Code Playgroud)

每个实现的类都IDisposable需要包装在一个using块中,以确保Dispose始终调用该方法.


更新:

Elaborating:在.NET中有IDisposable接口,它定义了Dispose方法.实现此接口的类(如文件流,数据库连接,读取器......)可能包含指向非托管资源的指针,并且确保释放这些非托管资源/句柄的唯一方法是调用Dispose方法.所以在.NET中确保即使抛出异常也会调用某些代码是使用try/finally语句:

var myRes = new MyResource(); // where MyResource implements IDisposable
try
{
    myRes.DoSomething(); // this might throw an exception
}
finally
{
    if (myRes != null)
    {
        ((IDisposable)myRes).Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

编写C#代码的人很快就意识到每次处理可处理资源时写这个都是PITA.所以他们引入了using声明:

using (var myRes = new MyResource())
{
    myRes.DoSomething(); // this might throw an exception
}
Run Code Online (Sandbox Code Playgroud)

这有点短.

  • 希望啤酒不会泄漏.现在这是一个真正的问题 (4认同)
  • @Mike Caron,是的,之后,你有没有试过这个文件?你有没有:`这个文件无法打开,因为它已被其他进程异常使用?请使用您正在处理IDisposable资源的`using`imeime.为什么我们的生活会变得更加容易?我们为什么要问所有这些问题?在这个世界上没有任何东西可以说服我`StringReader reader = new StringReader(...);`是很好的代码.如果在C#9.0中微软在StringReader中引入了一些新概念怎么办?然后代码可能实际上成为问题并且中断. (3认同)
  • @Darin:我认为教好的做法包括说实话 - 特别是,如果你告诉别人他们的代码是"泄漏严重"而不是,并且他们认为如果"泄漏严重"在这种情况下不会伤害他们,也许它不会在其他时候伤害他们,你会招来麻烦.更诚实,但*也*给予良好的实践,IMO. (3认同)
  • 你说它正在"严重"泄漏 - 但在"StringReader"的情况下,实际上什么都不会泄露 - 在这方面它就像`MemoryStream`.无论如何最好处理它,只是为了最佳实践,如果你改变代码使用类似*需要清理的东西......但它并没有真正泄漏. (2认同)

Jon*_*eet 6

在这种特定情况下,你的代码实际上没有泄漏任何东西,因为StringReader没有任何资源可以清理,就像MemoryStream没有.(随着MemoryStream可以仍然最终需要处置的,如果你使用它异步远程处理或它......但在简单的情况下,它并不重要.)

但是,处理IDisposable原则上实现的任何东西都是一个好主意.这样可以避免泄漏(可能是暂时的)非托管资源,例如文件句柄.

例如,假设您将代码更改为:

StreamReader reader = new StreamReader("file.txt");
...
Run Code Online (Sandbox Code Playgroud)

如果你不在reader这里关闭或处理(在一个finally块或通过一个using语句)它将保持文件打开,直到任何类型直接持有OS文件句柄最终确定.明确地处理事物不仅可以更早地释放非托管资源 - 它还可以将最终化对象从终结队列中取出,这意味着它们可以在之前进行垃圾回收.