2010-01-07 36 views
6

当我意识到自己对清理资源几乎一无所知时,我正在试验如何摆脱应用程序中的内存泄漏。我做了一些研究,并希望只调用.dispose()将解决我所有的问题。我们的数据库中有一张表,其中包含约65,000条记录。显然,当我从数据适配器填充数据集时,内存使用率可能会非常高。当我在数据集上调用dispose方法时,我惊讶地发现没有释放内存。为什么发生这种情况?清除数据集也无济于事。.dispose()方法是否可以执行任何操作?

回答

25

IDisposable因此Dispose不用于降低内存压力,尽管在某些情况下它可能会用于确定性清理。

请考虑这一点,您将构建一个维护与数据库服务器的主动和开放连接的对象。此连接使用您的计算机和服务器上的资源。

当然,当你完成这个任务时,你可以将对象留下,最终它会被垃圾回收器拾取,但是假设你想确保至少释放资源,并且因此连接关闭,当你完成它。这是IDisposableDispose进场。

它用于清理由对象管理的资源。

但是,它不会释放分配给该对象的托管内存。这仍然留给了垃圾收集器,稍后会在这个时候启动。

你真的有内存问题,或者你只是看看在任务管理器或类似的内存使用情况,去“有点高。”?

如果是后者,那么你应该暂时把它留下。如果你的内存少,那么.NET会更经常地运行垃圾回收,所以除非你处于一种情况,或者可能会怀疑你很快会遇到内存溢出的情况,否则你可能不会有任何问题。

让我解释我的意思是“少运行”。

如果您的计算机有8GB的内存,并且只有Windows和记事本运行,那么大部分内存都可用。当你现在运行你的程序时,即使它将小数据块加载到内存中,也可以长时间保持这种状态,并且内存使用量将稳步增长。确切地说,当GC启动并尝试减少你的内存占用我不知道,但我几乎可以向你保证,你会想知道为什么它变得如此之高。

让我们只是为了争辩说,你的程序最终会使用2GB的内存。

现在,如果你在一台内存较少的机器上运行你的程序,GC将会更频繁地出现,并且会降低一个下限,这可能会使内存使用量低于500MB甚至更少。

这里要注意的重要组成部分,是为了让你得到多少内存应用的精确图像实际上需要,那么你可以不依靠任务管理器或测量它类似的方式,你需要的东西更有针对性。

+0

我的程序可以达到700,164k。考虑到我的客户可能有低端电脑,这并不好。 – broke 2010-01-07 22:13:55

+6

这意味着你没有阅读我的答案。尝试加载几个大型应用程序,以便在启动自己的程序之前,您的内存少于700,164k(包括虚拟内存)。然后尝试加载它,它可能仍然有效,除非你将更多的数据加载到内存中以供使用,在这种情况下,gc根本没有任何帮助,只需要减少处理的数据量在任何给定的时间。 – 2010-01-07 22:18:23

+0

好吧生病了试一试。 – broke 2010-01-07 22:20:30

4

调用Dispose()只会释放非托管资源,例如文件句柄,数据库连接,非托管内存等。它会释放垃圾回收内存,而不是而不是

垃圾收集内存只会在下一次收集时被释放。通常当应用程序域内存满了时。

3

我将在这里指出一些尚未明确提及的内容:如果组件的开发人员编写了代码,则调用Dispose()将只清理(免费)非托管资源。

我的意思是:如果你怀疑你有内存泄漏,呼吁Dispose()是不会解决它如果原开发商做了糟糕的工作,而不是正确地释放非托管资源。多一点信息,check this blog post。注意声明 Dispose的行为由开发人员定义。

1

有些对象会要求一个或多个其他实体代表它做某件事,直到进一步通知为止,从而损害其他实体。如果这样做的对象在没有通知前实体不再需要其服务的情况下消失,那些实体将继续无用地代表不再需要它们的对象行事,继续损害其他想要的对象使用它们。

在许多情况下,对于“乔治”对象告诉外部实体“乔”不再需要它的服务,乔治将不得不知道服务不再需要。有两种常见的方式可以在.NET中发生,最终确定和IDIsposable

如果一个对象覆盖了一个名为Finalize的方法,那么当创建该对象时,.NET垃圾回收器会将它添加到具有已注册终结器的对象列表中。如果GC发现不存在对该列表以外的对象的根引用,则GC将从该列表中删除该对象,并将其添加到应该尽快调用其方法的根对象强队列中。这样的对象然后可以使用其方法来通知其他实体不再需要其服务。

虽然基于定案的清理有时可以奏效,但并不保证及时性。在微软的设计过程中,微软可能已经打算将最终确定作为主要的清理方法,但由于各种原因,它无法安全地依赖。

其他清理方法,应该是人们努力的重点,是IDisposable。基本上,IDisposable背后的想法很简单:对于实现IDisposable的每个对象,应该有一个实体(通常是对象或嵌套执行范围),它负责确保该对象的IDisposable.Dispose方法将在某个生命周期内的某个时间被调用宇宙(这意味着某个时候对对象的引用仍然存在),并且最好只要代码能够告诉对象的服务将不再需要。

请注意,IDisposable.Dispose一般承诺,任何被要求代表对象做任何事情的外部实体将被告知他们不再需要这样做,但是这样的承诺并不意味着实体的数量是非-零。如果一个对象没有要求任何外部实体代表它做任何事情,那么传递一个“全部”这样的实体的消息根本不需要做任何事情。另一方面,在某些情况下,一个方法可能不会做任何事情的事实并不意味着它在任何情况下都不会做任何事情,也不意味着在它会做某件事的情况下没有做到这一点有害影响。

相关问题