关于.net中内存管理的疑虑

cla*_*aws 5 .net c# garbage-collection memory-management

我正在从"Professional C#"一书中学习C#中的内存管理

垃圾收集器的存在意味着您通常不会担心您不再需要的物体; 您将简单地允许对这些对象的所有引用超出范围,并允许垃圾收集器根据需要释放内存.但是,垃圾收集器不知道如何释放非托管资源(例如文件句柄,网络连接和数据库连接).当托管类封装对非托管资源的直接或间接引用时,您需要进行特殊配置以确保在对类的实例进行垃圾回收时释放非托管资源.

定义类时,可以使用两种机制自动释放非托管资源.

  1. 将析构函数(或终结器)声明为您的类的成员.
  2. 在类中实现System.IDisposable接口.

我不明白一些事情:

  1. "非托管资源(例如文件句柄,网络连接和数据库连接)".关于他们的重大事项是什么?为什么他们不受管理?(或)为什么GC不能管理这些资源?

  2. 我们将在一个类的终结器或Dispose()方法中放置什么代码以及该代码究竟是什么样的?使用这些资源的一些例子会有很多帮助.

Dav*_*art 11

.NET框架上的某些类只是Windows API或第三方程序集的包装.这些API不是托管代码(它们可以用C++编写,也可以是旧的COM程序集),垃圾收集器不知道应用程序何时不再需要它们.

例如,当您打开磁盘文件时,它将保持打开状态,直到您告诉它关闭该文件.如果在不关闭文件的情况下销毁指向文件的指针(即离开作用域),则此文件将保持打开并锁定.

在Framework上为这些类实现的Dispose方法调用以干净的方式完成实例所需的内部Close方法.所以包装非托管代码的所有类都应该实现Disposable接口,以确保它实现的关闭方法.

然后,当您使用using语句对该类进行实例化时,这是一个很好的做法,因为当您离开作用域时,会自动调用Dispose方法.


Mar*_*rén 6

这里真正的问题是紧迫性.当垃圾收集器明确跟踪内存时,它将知道何时需要通过清除未引用的对象来释放内存.这可能每分钟发生几次,或者每小时发生一次,甚至从不发生(如果不需要创建新对象).但重要的是它确实在需要时发生.

但记忆并不是唯一有限的资源.拿文件.通常,一次只有一个应用程序可以打开文件,因为如果有几个人试图写入同一个文件,它可能会变得混乱.数据库的连接数量有限.等等.垃圾收集器不跟踪任何这些资源.并且它不知道关闭它们有多紧急.

当然,您可以打开一个FileStream并从中读取,而不会在之后关闭它.如果你取消对对象的引用,最终垃圾收集器可能会决定收集FileStream对象,它将运行Finalizer并且文件将被正确关闭.但这可能需要很长时间,同时文件被锁定.

对于数据库连接,它更加紧迫,因为可用的集合数量非常有限,因此如果打开太多连接而不处理它们,最终会出现错误,因为您将拥有一堆具有开放连接的数据库对象躺在垃圾收集器队列中等待.

因此,正确处理一次性物品是一种很好的做法.有时你可以逃避不这样做,但它的风格很差.如果一个对象实现了IDisposable,那是因为它要你在使用它时清理它.