C# 处置 IDisposable

发布于 2024-10-28 08:30:46 字数 298 浏览 6 评论 0原文

有人可以解释一下如果您不Dispose某些IDisposable实体(通过using或直接Dispose调用)

这是否总是导致内存泄漏,如果是,C# 内存泄漏是否与 C++ 内存泄漏类似,它们很容易导致从这个角度来看,崩溃还是 C# 沙箱更安全?

谢谢。

Could someone explain what might happen if you don't Dispose some IDisposable entity (by using or direct Dispose call)?

Does this always result in a memory leak and if yes, are C# memory leaks similiar to C++ memory leaks, where they could easily lead to a crash or is C# sandbox safer from this point of view?

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

你的心境我的脸 2024-11-04 08:30:46

这完全取决于所讨论的对象。

对象可能实现 IDisposable 的原因有五种:

  1. 它拥有本机资源。
    如果是这样,它应该在其终结器中调用Dispose,因此,如果您忘记处置它,就会发生原生资源的持续时间超过必要的时间。
    如果您一次创建大量此类对象并且不处理它们,则可能会耗尽本机资源。

  2. 它拥有一次性的托管对象。
    它拥有的对象也属于这些类别之一;查看相关类别。

  3. 它对自身有一个持久的引用,不会自然释放(例如,它处理静态事件)
    dispose 方法将清除此引用(例如,取消注册事件处理程序)
    如果是这样,不调用Dispose将导致它永远持续下去。

  4. 它继承了一个可处置的基类,例如StreamComponent,但实际上并不需要被处置。 (例如,MemoryStream
    如果是这样,不调用 Dispose 是无害的,除非该类将来发生更改。

  5. 它在其 Dispose 方法中执行一些操作,人们应该在 using 语句中调用这些操作(例如,using (Html.BeginForm() { ... })
    如果是这样,不处置该对象将违背其执行该操作的整个目的。

It completely depends on the object in question.

There are fourfive reasons that an object might implement IDisposable:

  1. It owns native resources.
    If so, it should call Dispose in its finalizer, so all that happens if you forget to dispose it is that the native resources last longer than necessary.
    If you create lots of such objects at once and don't dispose them, you may run out of native resources.

  2. It owns managed objects that are disposable.
    The objects that it owns will fall also into one of these categories; see the relevant category.

  3. It has a long-lasting reference to itself that won't be freed naturally (eg, it handles a static event)
    The dispose method would clear this reference (eg, unregister the event handler)
    If so, not calling Dispose will cause it to last forever.

  4. It inherits a disposable base class, such as Stream or Component, but doesn't actually need to be disposed. (eg, MemoryStream)
    If so, not calling Dispose is harmless, unless the class changes in the future.

  5. It performs some action in its Dispose method that people should call in a using statement (eg, using (Html.BeginForm() { ... })
    If so, not disposing the object will defeat its entire purpose, which is to do that action.

为你鎻心 2024-11-04 08:30:46

值得指出的一个区别是.NET 管理内存,而不是资源IDisposable 的设计使得实现此接口的类的客户端可以确定性地处置资源。

Joe Duffy 在其题为 DG 更新:处置、最终化的文章中非常清楚地阐述了这种区别和资源管理

CLR 的垃圾收集器 (GC) 会
内存管理方面的出色工作
直接分配给 CLR 对象,但是
显然不是为了处理
具有非托管内存和操作系统管理
资源。

One distinction that is worth pointing out is that .NET manages memory, but not resources. IDisposable is designed so that clients of classes implementing this interface can dispose resources deterministically.

Joe Duffy states the distinction pretty clearly in his post entitled DG Update: Dispose, Finalization, and Resource Management:

The CLR’s garbage collector (GC) does
an amazing job at managing memory
allocated directly to CLR objects, but
was explicitly not designed to deal
with unmanaged memory and OS-managed
resources.

懒的傷心 2024-11-04 08:30:46

任何事情都可能发生,因为一个类可以自由地实现Dispose,但是他们选择这样做。

通常被处置的不是托管资源(通常会自行处理),而是非托管资源,例如数据库连接、文件锁等。

一般来说,当垃圾收集处理它时,Dispose 会在终结器中调用,但是例如,如果您写入文件并且您不关闭它(Dispose 会这样做),那么您将阻止任何其他程序(包括同一程序中的代码的其他部分)打开该文件(可能在只读模式下除外)。

如果您保留数据库连接的时间超过必要的时间,您可能会达到最大打开连接数并停止您的应用程序使用数据库。

一般来说,如果一个类实现了 IDisposable,则表示我有一些东西需要处理,并且应该尽快处理它,而不是等待垃圾收集器出现。

Any number of things might happen because a class if free to implement Dispose however they choose to.

What is usually disposed is not managed resources (which usually take care of themselves) but unmanaged ones such as database connections, file locks, etc.

Generally speaking Disposed is called in the finalizer when garbage collection gets around to it, however for instance if you write to a file and you don't close it (which Dispose does) then you're preventing anything other program (including other parts of your code in the same program) from opening that file (except possibly in read-only mode).

If you hold on to database connections for longer than necessary you could hit the max open connections and stop your app from using the database.

In generally if a class implements IDisposable it's saying that I have something that needs to be disposed, and it should be disposed as soon as possible, not waiting for the garbage collector to come around.

坚持沉默 2024-11-04 08:30:46

最可能的影响是资源锁定(例如,您打开文件句柄但不关闭它 - 最终终结器将处理它)或耗尽(例如,您执行绘图操作但不执行此操作)丢弃物品)。

如果内存压力不足以导致 GC(这将启动最终确定过程)及时使用更多资源,这可能会成为一个问题,尤其是对于后一个问题。这会导致有用的错误,如“GDI+ 中发生的一般错误”。

如果写得不好的对象只有 Dispose 方法而没有终结器,则可能会泄漏内存,但这种情况很少见。另一种可能性是 Dispose 方法取消订阅静态事件。这也可能是一个严重的问题,并且会“泄漏”内存。

The most likely effects will be resource locking (e.g. you open a file handle and don't close it - eventually the finalizer will take care of it) or exhaustion (e.g. you do drawing operations and don't dispose of the objects).

This can be a problem, especially with the latter issue, if the memory pressure isn't sufficient to cause a GC (which will kick off the finalization process) in time to use more of the resources. This leads to helpful errors as "a generic error occurred in GDI+."

Poorly written objects may leak memory if they have only a Dispose method and no finalizer, but this is a rarity. Another possibility is that the Dispose method unsubscribes from static events. This could also be a significant problem and will "leak" memory.

无言温柔 2024-11-04 08:30:46

不调用 .Dispose() 可能会导致内存泄漏。否则,不调用 Dispose() 只会导致 GC 延迟收集。总体而言,效果将完全取决于实例化的对象(请参阅 SLAks 以获取精彩的项目符号列表)。可以这么说,通过实现 IDisposable,您就有责任清理混乱。

实现应该做的是告诉 GC(垃圾收集器)它应该抑制收集,因为你要处理它。这样,当在 IDisposable 对象上调用 Dispose() 方法时,您应该负责清理工作,即对该类中的对象调用 Dispose()、清除集合等。

并且,仅供参考,using{...} 子句只能用于实现 IDisposable 的对象,因为在右括号处会自动调用 Dispose() 方法:

using (MyDisposableObject dispObj = new MyDisposableObject())
{
    // use dispObj for some work
}    // dispObj.Dispose() is automatically called here

Not calling .Dispose() could result in a memory leak. Otherwise, not calling Dispose() will simply result in delayed collection by the GC. Overall, the effects will completely depend on what objects are instantiated (see SLaks for a great bullet list). By implementing IDisposable, you are taking responsibility for cleaning up your mess, so to speak.

What implementation should do is tell the GC (Garbage Collector) that it should suppress collection because you are going to take care of it. That way, when the Dispose() method is called on your IDisposable object, you should have taken care of clean up - i.e., calling Dispose() on objects within that class, clearing collections, etc.

And, FYI, the using{...} clause can only be used on objects implementing IDisposable because at the closing bracket the Dispose() method is called automatically:

using (MyDisposableObject dispObj = new MyDisposableObject())
{
    // use dispObj for some work
}    // dispObj.Dispose() is automatically called here
谁许谁一生繁华 2024-11-04 08:30:46

IDisposable 旨在包装非托管资源(即不是 .NET 内存)。因此,如果您不处置它们,您将泄漏打开的数据库连接、窗口句柄、文件句柄等内容,具体取决于您未能处置的 IDisposable 类型。

因此,这并不是真正的内存泄漏,但当您用完非托管资源时,它可能会导致性能下降并最终导致崩溃。

IDisposable is meant to wrap an unmanaged resources (i.e. not .NET memory). So if you don't dispose them, you will leak things like open database connections, Window handles, file handles, etc. depending on what type of IDisposable you're failing to dispose.

So it's not truly a memory leak, but it can lead to performance degradation and eventually a crash as you run out of the unmanaged resources.

墨小墨 2024-11-04 08:30:46

有些对象在其存在期间会对外部实体执行一些需要它们清理的操作。有一个非常严格的约定,即此类对象应在实际中实现 IDisposable,并在调用 IDisposable.Dispose() 方法时执行任何所需的清理。如果系统发现对象已被放弃,系统允许对象请求通知,但不能保证此类通知会及时发生并发挥作用。此外,除非非常小心,否则此类通知可能会提前触发并尝试清理仍在使用的内容。

除非您知道可以安全地放弃特定类的 IDisposable 对象,否则不要这样做。只要可行,请务必清理干净。 “最终化”(通知对象已被放弃的过程)是危险的,并且可能会产生许多 Heisenbug。如果存在任何实际的替代方案,请避免依赖它。

Some objects will, during their existence, do things to outside entities that they are expected to clean up. There is a very strong convention that such objects should whenever practical implement IDisposable and perform any required cleanup when the IDisposable.Dispose() method is called. The system allows objects to request notification if it notices that they've been abandoned, but there's no guarantee that such notifications will happen in time to be useful. Further, unless one is careful, it's possible for such notifications to fire early and try to clean up things that are still in use.

Unless you know that a particular class of IDisposable object may be safely abandoned, don't. Always clean up after yourself whenever practical. "Finalization" (the process of notifying objects they've been abandoned) is dangerous and can create many Heisenbugs. Avoid relying on it if any practical alternative exists.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文