为什么不是';我的.NET垃圾没有被收集

本文关键字:NET 我的 为什么不 | 更新日期: 2024-10-23 14:44:13

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

我们还能够"卸载"一个帐户,从而删除内存中的所有对象(或者至少我们认为我们删除了)。无论我让应用程序在我的电脑上休眠多久,它似乎都不会将分配的内存减少到预加载帐户状态,即使我使用WeakReference查看对象状态,它也会说它不存在。

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

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

我应该继续使用GC.Collect吗?考虑到运行GC.Collect相对于从DB加载帐户的成本是最低的,即使显式调用它被认为是"坏做法"?

为什么不是';我的.NET垃圾没有被收集

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

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

OM异常可能不是由此引起的,而是您在其他地方发生了内存泄漏,或者某些用户试图加载多个帐户(甚至是大于0.5GB的帐户)。考虑对应用程序进行一些内存分析。(我已经为此使用了YourKit探查器,它非常容易使用)

想想看,如果你的进程是x86,那么它的最大可用空间为2GB,所以有了这样的大数据,你就会达到极限。

我不知道你是否在代码中这样做了,但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();
}
相关文章: