Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么';CLR处理清除代码?_C#_.net - Fatal编程技术网

C# 为什么';CLR处理清除代码?

C# 为什么';CLR处理清除代码?,c#,.net,C#,.net,我刚刚开始使用.NET框架。今天,我学习了IDisposable接口和dispose()方法。我学到了一些关于它的东西: dispose()应包含与对象对应的清理代码(如关闭任何对象占用的任何资源-文件或数据库连接等) 我还被告知,如果我们不在dispose()方法中执行,同样的操作也可以在析构函数中执行,但这不能确保立即执行,我们将任由GC摆布 如果我们根本不提供任何清理代码,GC将强制终止与对象所持有的资源的所有连接。因此,我们应该自己处理清理代码 但我很好奇为什么CLR不能自己处理这个问题

我刚刚开始使用.NET框架。今天,我学习了
IDisposable
接口和
dispose()
方法。我学到了一些关于它的东西:

dispose()
应包含与对象对应的清理代码(如关闭任何对象占用的任何资源-文件或数据库连接等)

我还被告知,如果我们不在
dispose()
方法中执行,同样的操作也可以在析构函数中执行,但这不能确保立即执行,我们将任由GC摆布


如果我们根本不提供任何清理代码,GC将强制终止与对象所持有的资源的所有连接。因此,我们应该自己处理清理代码

但我很好奇为什么CLR不能自己处理这个问题?它负责内存管理和垃圾收集。因此,它应该非常清楚地知道哪个对象持有哪些资源,以及该对象何时消亡。那么,它也应该能够取消这些资源的分配


我问了几个人。我得到的答案是,这是因为我们需要优雅地关闭它,而as GC会强制关闭它。这是真正的原因吗?

IDisposable接口为您提供了清理未管理资源的方法。CLR仅为您管理托管资源


换句话说,CLR只知道如何清理它管理的东西。如果您打开与系统其余部分的连接(如打开文件、数据库连接等),这些都是您的责任,您需要告诉CLR您希望它如何为您清理这些连接。

在.NET中,GC知道的托管代码远远多于。这涉及到大量的非托管代码:所有的文件句柄、数据库连接、网络套接字等等。。。所有这些都是普通的非托管Win32代码。你甚至不能相信,在你从漂亮的C应用程序调用的几乎每一个Bcl函数中,你会碰到像C++编写的大量非托管函数(并且可能禁止VB6),并深深地隐藏在OS本身的内部。所有这些函数都在分配非托管内存、句柄等。。。管理世界不知道那里发生了什么

例如,每次打开文件(
FileStream
)时,基本上都是在幕后调用非托管Win32函数。此函数用于直接从文件系统分配非托管文件句柄。NET和GC完全无法跟踪此非托管代码及其所做的一切。这就是为什么这些类实现IDisposable接口。这样,您就可以始终将它们的实例包装在中,并确保始终调用Dispose方法,即使在发生异常的情况下也是如此,而且要尽快调用Dispose方法。Dispose方法将负责调用另一个非托管函数来清除它创建的混乱

因此,基本上您可以考虑IDisposable接口的方式如下:

有一天,当我们有一个完全管理语言编写的操作系统(例如,来自微软研究院的语言)时,我们可能不再需要IDisposable,因为GC将能够完全替换它,因为它将了解该系统中发生的一切


IDisposable
Dispose()
的要点是,您应该清理非托管的内存。这就是.NET没有分配的内存,它来自外部源,因此GC无法知道它。所以它不能自动为你清理。本质上,这正是托管内存和非托管内存之间的区别;-)


通常,您应该实现
Dispose()
来清理类使用的任何非托管资源,并实现finalizer来调用
Dispose()
。不过,终结器只是一种保护。如果调用者忘记正确处理您的类,它将确保最终清理这些资源。

IDisposable接口只是一种约定,允许您决定性地处理托管和非托管资源。它本身并不能取代垃圾收集或做任何涉及垃圾收集器本身的事情

对于非托管资源,这一点更为明显,因为除非对这些资源进行处理(在终结器中或使用确定性处置),否则它们将一直作为内存泄漏,直到进程结束。对于托管内存,如果不确定地处置项目,GC将不确定地收集这些项目(假设最终有资格收集),因为它们是受管理的(这也是dispose模式在终结器路由中不包括托管项目的原因)

IDisposable
本身不起任何作用,它只是一个可识别的接口(并且在带有
using
关键字的代码中受支持),人们希望在处理使用可消耗资源、非托管内存、外部项目等的项目时能找到它


CLR不可能知道外部项何时完成。这完全取决于应用程序的流程。如果您碰巧也不知道何时处置对象,则终结器语法非常有用。如果在自定义类上实现终结器,垃圾收集进程将在最终收集之前运行此终结器。这是你最后一次整理东西的机会。

它只能负责.NET对象的内存管理。任何需要使用非托管资源的代码(因为它与C++库交互)都落在垃圾收集器的BiLiWik之外。所有这些代码都需要被告知何时以老式方式释放其资源。

我们按顺序使用Dispose