C# 对.net内存管理的质疑

C# 对.net内存管理的质疑,c#,.net,memory-management,garbage-collection,C#,.net,Memory Management,Garbage Collection,我从《专业C》一书中学习了C语言中的内存管理 垃圾收集器的存在 意味着你通常不会担心 关于你不再需要的物品; 您只需允许所有引用即可 使这些对象超出范围 并允许垃圾收集器 根据需要释放内存。但是, 垃圾收集器不知道如何 释放非托管资源(如文件 句柄、网络连接和 数据库连接)。管理时 类封装直接或间接的 对非托管资源的引用,您可以 需要对 确保非托管资源 当 类被垃圾收集 定义类时,可以使用 两种自动释放的机制 非托管资源的管理 将析构函数(或终结器)声明为类的成员 在系统中实现System.ID

我从《专业C》一书中学习了C语言中的内存管理

垃圾收集器的存在 意味着你通常不会担心 关于你不再需要的物品; 您只需允许所有引用即可 使这些对象超出范围 并允许垃圾收集器 根据需要释放内存。但是, 垃圾收集器不知道如何 释放非托管资源(如文件 句柄、网络连接和 数据库连接)。管理时 类封装直接或间接的 对非托管资源的引用,您可以 需要对 确保非托管资源 当 类被垃圾收集

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

  • 将析构函数(或终结器)声明为类的成员
  • 在系统中实现System.IDisposable接口 班级
  • 有几件事我不明白:

  • “非托管资源(如文件句柄、网络连接和数据库连接)”。他们有什么大不了的?他们怎么会不受管理?(或者)为什么GC不能管理这些资源

  • 我们将在类的finalizer或Dispose()方法中放置什么代码,以及该代码的确切外观?使用这些资源的一些示例将非常有用

  • 1.)GC不知道如何正确关闭外部资源。当然,他可能会切断网络连接(事实上,如果你不断开连接,他会这么做,比如数据库连接)。但是数据库没有收到关闭连接的通知

    文件流也是如此。缓冲区里还有东西吗?是否必须在关闭文件句柄之前将其写入文件?GC不知道这一点——访问代码知道

    2.)是由此得出的结论。 因此,如果您有打开的文件流和内部缓冲区-在dispose方法中,您将刷新缓冲区,将其写入文件并关闭文件hanlde

    通常,您不直接访问数据库。您可以使用库来为您管理这些


    在大多数情况下,如果正在处理您的类,则处理这些外部资源管理器(Db连接、文件流、网络类)就足够了。

    有关2)请参见此处:

    在.NET framework上的某些类只是Windows API或第三方程序集的包装。这些API不是托管代码(它们可以用C++编写,或者它们是旧的COM组件),垃圾回收器不知道应用程序不再需要什么时候。p> 例如,当您打开一个磁盘文件时,它将保持打开状态,直到您告诉它关闭该文件为止。如果在不关闭文件的情况下销毁指向该文件的指针(即离开作用域),该文件将保持打开和锁定状态

    在这些类的框架上实现的Dispose方法调用以干净方式完成实例所需的内部Close方法。因此,包装非托管代码的所有类都应该实现一次性接口,以确保实现了关闭方法


    然后,当您实例该类时,最好使用using语句,因为当您离开作用域时,会自动调用Dispose方法。

    非托管资源是操作系统拥有和控制的资源的句柄(当然不是内存)

    当对象不再有任何引用时,GC不会立即清理内存——它可能会离开对象很长一段时间。如果它对文件、网络和图形句柄执行此操作,则可能会占用大量操作资源,并且只会偶尔释放它们


    为了将这些非托管资源释放回操作系统,您需要通过处置它们来显式地释放它们。因此使用IDisposable和using关键字。

    这是一个很好的问题,许多开发人员似乎不理解

    在较高级别上,托管资源是由.Net分配和跟踪的资源。资源使用的内存来自分配给.Net的池,.Net运行时跟踪托管资源之间的所有引用。这种跟踪(我确信这是一个错误的术语,但在这里就足够了)允许.Net运行时知道给定资源何时不再被使用,从而有资格被释放。因此,非托管资源是指在该.Net托管池之外分配的、运行时不跟踪的资源。通常,这些是对操作系统或外部应用程序资源的引用。.Net运行时无法“查看”非托管资源有各种复杂的原因,但我喜欢这样想:.Net是一个封闭的开发花园,您必须进入才能使用。你可以在墙上戳一个洞看外面(例如,PInvoke),但你不能拥有另一边的资源

    现在,进入问题的第二部分。比尔·瓦格纳(Bill Wagner)在他的书中对如何实现Dispose方法及其原因进行了大量讨论。关于这一点,也有一些非常好的答案


    希望这能有所帮助。

    这里真正的问题是关于紧迫性。当垃圾收集器显式跟踪内存时,它将知道何时需要通过清理未引用的对象来释放内存。这种情况可能一分钟发生几次,或一小时发生一次,甚至永远不会发生(如果不需要创建新对象)。但重要的是,它确实在需要的时候发生

    但内存并不是唯一有限的资源。拿文件。通常一次只有一个应用程序可以打开一个文件,因为如果几个人试图写入同一个文件,文件可能会变得混乱。数据库的连接数量有限。等等垃圾收集器不跟踪这些资源中的任何一个。而且它已经