ASP.NET网站内存使用率相当高

时间:2010-08-04 12:41:48

标签: .net asp.net memory-management memory-leaks

我有一个ASP.NET网站,它会在大约3-4天内使用大约2GB的物理内存,这听起来真的很糟糕。目前,我已经配置IIS以在达到500mb时重新启动应用程序池进程。我想尝试找出问题所在。

在.NET中创建对象的新实例时,我觉得它不需要被释放,因为.NET垃圾收集器会为我做这件事。

是这种情况还是这可能是我遇到问题的原因之一?

7 个答案:

答案 0 :(得分:17)

.NET将非常有效地为您管理垃圾收集。在实现IDisposable的类型上,调用Dispose方法是明智的,这可能不是你的问题。由于很多原因,.NET中可能发生内存泄漏。以下是一些:

  • 您在会话中为每个用户缓存了太多数据。
  • 您在应用程序缓存或静态变量(如字典)中的应用程序级别缓存了太多数据。
  • 您可以在会话或应用程序级别存储Web控件(或用户控件)。
  • 您可以将实例挂接到静态类型上的事件或保持被引用的类型(因为它们存储在缓存中)。

我希望这会给你一些关于在哪里看的想法。

更新:您应该观看有关ASP.NET调试的this video

更新2: 关于您对我的回答的评论如下。 CLR将收集所有托管内存,因此将使用new创建的所有对象都将被收集。从这个意义上说,对象是否实现IDisposable并不重要。但是,有很多时候您需要直接或间接使用本机资源(例如文件句柄,图形句柄,数据库连接,使用native-thus unmanaged-memory)。 CLR不知道如何释放这些资源。因为这个.NET有终结器的概念。终结器是类的开发人员可以实现的虚拟方法。执行此操作时,CLR将在该类型的实例未被引用之后以及在收集之前调用此方法。终结器通常包含释放这些资源的逻辑。换句话说,当一个类型需要本机资源时,它通常会有一个终结器方法,允许该类型释放这些资源。

CLR怎么样,故事在这里结束。 CLR没有具体处理实现IDisposable接口的对象。然而,.NET垃圾收集器本质上是不确定的。这意味着您不知道它何时运行以及它是否运行。这意味着在清理本机资源之前可能需要很长时间(因为终结器只会在收集后调用)。但是,对于许多资源,一旦完成它们就必须立即释放它们。例如,当您不关闭数据库连接或通过System.Drawing命名空间在.NET中使用GDI +时,您往往会快速耗尽数据库连接。

因此引入了IDisposable接口。同样,CLR和垃圾收集器不会查看此接口。它是类型与其用户之间的契约,允许其用户直接释放对象的底层资源。在正常设计中,对象的终结器和对象的Dispose方法都将调用将释放这些资源的相同私有或受保护方法。当类型实现IDisposable时,明智的做法是在完成它时调用它的Dispose方法,或者将对象包装在using语句中以允许本机资源的释放是确定性的

回到你的问题。 GC将收集所有托管对象,但本地资源不会。因此,类型可能实现终结器方法,这些对象通常也会实现IDisposable接口。对它们调用Dispose将明确并直接释放这些本机资源。

我希望这是有道理的。

答案 1 :(得分:6)

您的高内存使用可能有很多原因,但.NET中的垃圾收集是非常精确的。也就是说,它为你做了很多,但有时候并没有你想象的那么多。

具体来说,它只能清理没有活动引用的对象,所以如果你已经完成了一个类,但是某些东西仍然引用了它,你就会想要删除那个引用,这样GC可以为你恢复那段记忆。此外,如果您有任何非活动的打开连接(例如,对数据库或其他东西),请不要忘记关闭并处置它们。通常,我们将这些对象包装在using块中,如下所示:

using(SqlConnection conn = new SqlConnection(myConnString))
{ ...rest of code here }

这将自动关闭并处理连接。这是作为try ... finally块实现的,因此即使在using块中抛出异常,连接也将被关闭。

除此之外,答案是“个人资料,个人资料,个人资料”,直到找到您的泄密/瓶颈/其他任何内容。

答案 2 :(得分:3)

您应该注意以下几点:

首先,你在使用会话吗?它们是在proc或SQL会话中吗?如果他们正在进行中,超时设置为什么?如果你有一个非常长的超时,这可以解释为什么你使用这么多内存(用户会话将被存储很长时间)。

其次,处置对象。 .NET垃圾收集器将为您删除引用,但是当您创建实现IDisposable接口的对象时,应始终使用using关键字。

using(Foo foo = new Foo())
{
    ...
}

相当于:

Foo foo;
try
{
    foo = new Foo();
    ...
}
finally
{
    foo.Dispose();
}

它将确保您有效地处理对象。

如果您仍无法在代码中找到任何明显的内容,则可以从最常调用的方法开始对其进行分析。您可以找到有关优秀个人资料here的信息。这肯定会引导你找到问题的根源。

答案 3 :(得分:1)

.NET中的内存泄漏仍然存在。确实,大多数情况下你不需要释放对象(有一些例外,例如Graphics对象)但是如果你继续引用它们,它们就不会被垃圾收集,因为它们仍然被引用。 / p>

如果GC看到某个对象被引用到应用中的任何位置,则不会丢弃它。

查看这篇关于.NET内存泄漏的Code Project文章,以及如何定位和修复它们。

答案 4 :(得分:1)

如果您的ASP.NET应用程序使用事件(以及哪些事件没有),then you have to make sure you unsubscribe from the event

经验法则:

如果您使用+=订阅某个活动,则需要使用-=方法中的Dispose()取消订阅。

lots of resources on this topic,我已经在我工作的应用程序中遇到了一些痛苦,因为你的运行mill程序员没有意识到事件可能导致内存泄漏。

答案 5 :(得分:1)

当内存超过500 MB时,使用memory profiler(在内存转储或现场环境中),以获得哪些对象占用所有空间的线索。

在对您的开发环境进行概要分析时,您可能会看到一种特定的对象类型只会在您的网站上浏览时增长,而其他对象类型在全球范围内保持不变。

答案 6 :(得分:0)

虽然你不必显式释放内存并且垃圾收集器会为你做这件事,但是代码可能无意中持有对象的引用以防止它被收集 - 这本质上是一个内存泄漏。

在ASP.NET中,对象保持“活动”状态,而它们由应用程序和会话缓存引用。在不知道你的应用程序的任何事情的情况下,我建议你掌握一个内存分析器并仔细查看内存中的内容以及应用程序或会话缓存是否保留了它不应该存在的东西。