![]() |
1
23
这个
但是,PEN持有的任何非托管资源(例如,gdi+句柄)将不会被GC清除。GC只清理托管资源。打电话
现在,如果
有关此主题的先前评论,请参阅 answer . |
![]() |
2
26
这里应该做一些修正: 关于菲尔·德瓦尼的回答:
实际上,调用Dispose()并不能确定地导致.NET中的GC集合,即它不会立即触发GC,因为您调用了Dispose()。它只是间接地向GC发出信号,表示对象可以在下一个GC(用于对象所在的生成)期间被清除。换言之,如果对象位于Gen1中,那么在Gen1集合发生之前,它不会被释放。通过调用gc.collect()可以以编程方式和确定性方式导致gc执行集合的唯一方法之一(尽管不是唯一的方法)。但是,不建议这样做,因为GC在运行时通过收集应用程序运行时内存分配的度量来“调优”自身。调用gc.collect()将转储这些度量并使gc重新开始其“调优”。 关于答案:
这是不完整的。由于GC是非确定性的,因此释放模式( How to properly implement the Dispose pattern ,以便释放正在使用的资源-托管或非托管。它有 没有什么 处理您正在释放的资源。实现终结器的需要与您正在使用的资源类型有关—即,只有在您具有不可终结(即本机)资源时才实现一个资源。也许你混淆了这两者。顺便说一句,您应该避免使用safehandle类来实现终结器,该类包装通过p/invoke或com interop封送的本机资源。如果最终实现了终结器,那么应该 总是 实现释放模式。 我还没有看到有人提到的一个关键点是,如果创建了可释放对象,并且它有一个终结器(而且您永远不知道它们是否有——而且您当然不应该对此做任何假设),那么它将直接发送到终结队列,并至少为1个额外的GC集合而生存。 . 如果最终未调用gc.SuppressFinalize(),则将在下一个gc上调用该对象的终结器。请注意,Dispose模式的正确实现应该调用gc.SuppressFinalize()。因此,如果对对象调用Dispose(),并且它正确地实现了模式,则将避免执行终结器。如果不对具有终结器的对象调用Dispose(),则该对象的终结器将由GC在下一个集合上执行。为什么这样不好?.NET 4.6之前(含)的clr中的终结器线程是单线程的。想象一下如果你增加这个线程的负担会发生什么——你的应用程序性能取决于你知道在哪里。 对对象调用Dispose提供以下功能:
编辑 : 我刚刚注意到,关于 IDisposable (这里极度讽刺)确实说
正如任何人应该知道的,msdn是远远不正确的,从来没有提到或显示“最佳实践”,有时提供不编译的示例等。不幸的是,这是记录在这些话。然而,我知道他们想说的是:在一个完美的世界里,GC将清理所有 管理 为你提供资源(多么理想化);无论如何清理,它都不会。 非受管的 资源。这是绝对正确的。也就是说,生活并不完美,任何应用也不完美。 GC将只清理没有根引用的资源。 这主要是问题所在。 在.NET可以“泄漏”(或不释放)内存的大约15-20种不同方法中,如果不调用Dispose(),最有可能咬到您的方法是无法注销/取消挂起/释放/分离事件处理程序/委托。如果您创建了一个对象,该对象上连接了委托,并且没有调用Dispose()(也没有自己分离委托),那么GC仍然会将该对象视为具有根引用,即委托。因此,GC永远不会收集它。 @下面是Joren的评论/问题(我的回复太长,无法发表评论): 我有一篇关于建议使用的释放模式的博客文章-( 如何正确实现释放模式 )有时您应该将引用空出来,这样做永远不会有坏处。实际上,这样做会在GC运行之前做一些事情——它会删除对该对象的根引用。GC稍后扫描它的根引用集合,并收集那些没有根引用的引用。当这样做是好的时候,可以考虑这个例子:您有一个“classa”类型的实例,我们称它为“x”。X包含一个“ClassB”类型的对象-我们称之为“Y”。Y实现了IDisposable,因此,x应该对y做同样的处理。假设x在第2代中,或者loh和y在第0代或1代中。当在X上调用Dispose()并且该实现使对Y的引用为空时,对Y的根引用将立即移除。如果GC发生在第0代或第1代,那么Y的内存/资源将被清除,但X的内存/资源不是因为X位于第2代或LOH中。 |
![]() |
3
13
在将来某个不确定的时间(即当pen对象被垃圾收集并调用对象的终结器)之前,不会释放底层的gdi+pen句柄。这可能直到进程终止,也可能更早,但关键是它的不确定性。调用Dispose允许您进行确定性清理,强烈建议您这样做。 |
![]() |
4
2
正在使用的.NET内存总量是.NET部分+正在使用的所有“外部”数据。操作系统对象、打开的文件、数据库和网络连接都占用了一些不是纯.NET对象的资源。 图形使用钢笔和其他物体,它们实际上是操作系统的物体,保存起来“相当”昂贵。(您可以将笔换成1000x1000位图文件)。只有在调用特定的清理函数后,这些OS对象才会从OS内存中删除。当调用pen和bitmap dispose函数时,它们会立即为您执行此操作。 如果您不调用Dispose,垃圾收集器将在“将来的某个地方”来清理它们。 (它实际将调用析构函数/终结代码,该代码可能调用Dispose()) *在一台内存无限(或超过1GB)的机器上,未来的某个地方可能会非常遥远。在一台什么都不做的机器上,清理那块巨大的位图或非常小的笔可能要花30分钟的时间。 |
![]() |
5
2
|
![]() |
6
1
它将保留资源,直到垃圾收集器清理它为止 |
![]() |
7
1
取决于它是否实现终结器,并且它是否在其Finalize方法上调用Dispose。如果是这样,句柄将在GC上释放。 否则,句柄将一直保留,直到进程终止。 |
![]() |
8
0
有了图形材料,可能会很糟糕。 打开Windows任务管理器。单击“选择列”并选择名为“gdi对象”的列。 如果不处理某些图形对象,此数字将不断增加。 在旧版本的Windows中,这可能会使整个应用程序崩溃(据我记忆,限制是10000个),尽管不能确定Vista/7,但这仍然是一件坏事。 |
![]() |
9
-1
垃圾收集器无论如何都会收集垃圾,但在以下情况下它很重要: 如果您不调用不使用的对象上的Dispose,它将在内存中存活更长时间,并提升到更高的代,这意味着收集它的成本更高。 |
![]() |
10
-3
在我的脑海中,首先想到的是这个对象将在方法完成执行后立即被处理!,我不知道我从哪里得到这个信息!,对吗? |
|
Robert King · Unity C#语法问题-转换位置 1 年前 |
![]() |
JBryanB · 如何从基本抽象类访问类属性 1 年前 |
|
law · 检查答案按钮的输入字符串格式不正确 2 年前 |
![]() |
i_sniff_ket · 在unity之外使用unity类 2 年前 |