为什么不收集我的.NET垃圾?

时间:2015-03-06 11:59:24

标签: c# .net memory-management memory-leaks

我有一个数据密集的应用程序,用户可以在不同的帐户之间进行选择。一次只能选择一个帐户,这会强制从数据库加载数据。我可以在Windows任务管理器中看到,当我将一个帐户加载到大约半场演出时,分配给我的应用程序的内存正在增加。

我们也有能力卸载"一个帐户,我们在内存中删除所有对象(或至少我们认为我们这样做)。不过多久,我离开了应用程序运行在我的电脑处于休眠状态它似乎永远不会减少分配的内存回预加载帐户状态,甚至如果我看的对象状态使用WeakReference是说,它不是活的。

如果我在卸载方法结束时显式调用GC.Collect(),那么我可以看到内存未分配或至少Windows任务管理器中的程序大小下降。这是我们在内存方面真正想要实现的,因为一些用户遇到了内存异常。

我知道垃圾收集器正在进行一些管理,因为如果我加载后续帐户,内存永远不会真正增加超过半场演出,所以我认为GC已经收集了以前帐户的数据,就像它应该做的那样卸载帐户。

我是否应该继续使用GC.Collect,考虑到相对于从DB加载帐户而运行此成本的成本是最小的,即使它被认为是"不良做法"明确地称之为?

3 个答案:

答案 0 :(得分:0)

GC集合仅在certain events下触发(例如,托管进程的已分配内存全部使用,需要分配更多,因此首先检查它是否可以收集一些垃圾)。

OM异常可能不是由此引起的,但要么是其他地方有内存泄漏,要么某些用户正在尝试加载多个帐户(甚至大于0.5GB的帐户)。考虑对您的应用程序进行一些内存分析。 (我已经使用了YourKit profiler这很容易使用)

认为如果您的进程是x86,它最多可用2GB,因此使用这样的大数据并不罕见,您可以达到极限。

答案 1 :(得分:0)

根据您的描述,您似乎以某种方式保留了从db加载的项目的硬引用。如果您正在使用Entity框架或NHibernate,请检查您是否正在处理用于从数据库加载数据的上下文,因为它将保存您加载的所有内容的引用,以便提供更改跟踪功能。一般来说,确保你没有以某种方式保持参考,并注意有时这可能是棘手的;一个棘手的硬引用的一个很好的例子是在lamda方法中加载一些东西,它使用方法范围变量,由于在lamda方法中被引用,它被自动提升为类变量。

答案 2 :(得分:0)

我无法判断您是否在代码中执行了此操作,但using语句将调用您正在使用的命令的Dispose()方法。它可能有助于GC您遇到问题。否则你让系统处理它。唯一的问题是您使用的类必须实现IDisposable。

    using (SqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "sp_SaveSomething";
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter("@x", xxx));
    cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
    cmd.ExecuteNonQuery();
}