C# 对.net内存管理的质疑
我从《专业C》一书中学习了C语言中的内存管理 垃圾收集器的存在 意味着你通常不会担心 关于你不再需要的物品; 您只需允许所有引用即可 使这些对象超出范围 并允许垃圾收集器 根据需要释放内存。但是, 垃圾收集器不知道如何 释放非托管资源(如文件 句柄、网络连接和 数据库连接)。管理时 类封装直接或间接的 对非托管资源的引用,您可以 需要对 确保非托管资源 当 类被垃圾收集 定义类时,可以使用 两种自动释放的机制 非托管资源的管理C# 对.net内存管理的质疑,c#,.net,memory-management,garbage-collection,C#,.net,Memory Management,Garbage Collection,我从《专业C》一书中学习了C语言中的内存管理 垃圾收集器的存在 意味着你通常不会担心 关于你不再需要的物品; 您只需允许所有引用即可 使这些对象超出范围 并允许垃圾收集器 根据需要释放内存。但是, 垃圾收集器不知道如何 释放非托管资源(如文件 句柄、网络连接和 数据库连接)。管理时 类封装直接或间接的 对非托管资源的引用,您可以 需要对 确保非托管资源 当 类被垃圾收集 定义类时,可以使用 两种自动释放的机制 非托管资源的管理 将析构函数(或终结器)声明为类的成员 在系统中实现System.ID
在大多数情况下,如果正在处理您的类,则处理这些外部资源管理器(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方法及其原因进行了大量讨论。关于这一点,也有一些非常好的答案
希望这能有所帮助。这里真正的问题是关于紧迫性。当垃圾收集器显式跟踪内存时,它将知道何时需要通过清理未引用的对象来释放内存。这种情况可能一分钟发生几次,或一小时发生一次,甚至永远不会发生(如果不需要创建新对象)。但重要的是,它确实在需要的时候发生 但内存并不是唯一有限的资源。拿文件。通常一次只有一个应用程序可以打开一个文件,因为如果几个人试图写入同一个文件,文件可能会变得混乱。数据库的连接数量有限。等等垃圾收集器不跟踪这些资源中的任何一个。而且它已经