【问题标题】:Background thread increases memory usage后台线程增加内存使用
【发布时间】:2013-08-13 09:09:58
【问题描述】:

我有一个应用程序需要每 30 秒检查一次 db 以检查特定记录是否已更新。我为此使用后台线程。问题是当我在内存分析器中检查它时,应用程序的内存使用量不断增加。 这是代码

Form1:Base

Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Check));
t.IsBackground = true;
t.Start();

public void Check() {
            bool isUpdate = false;
            while (!isUpdate)
            {
                DataTable _data = CheckRecord();
                if (_data.Rows.Count > 0)
                {
                    isUpdate = true;
                }
                else
                {
                    Thread.Sleep(30000);
                }
            }
        }

public DataTable CheckRecord(){
return CHANNEL.GetData();
}

Form1 继承基础表单

Base:Form

ChannelFactory<ServiceClass> temp= new ChannelFactory<ServiceClass>("AAA");
ServiceClass ss=null;

public ServiceClass CHANNEL
{
    get {
        if(ss==null)
            ss=temp.CreateChannel();
        return ss;
    }
    }

【问题讨论】:

  • 首先线程本身需要内存。 可能是持续增加的原因是CheckRecord。你在创建一个大数据表吗?只要有足够的内存,GC 可能不会收集以前的_data 对象。因此,内存中可能有很多 DataTable 实例,即使它们不再可访问。你能用你的分析器检查这个吗?
  • 我同意@MatthiasMeid - 你没有明确地销毁你的DataTable,因此当你执行下一次检查时,你每次都有效地孤立它,如果CG没有'在您下次检查之前点击它,您的内存使用量将继续上升。如果您不使用DataTable,我会从数据库返回计数而不是数据本身。
  • 嗯,具体一点,内存分析器告诉你哪些对象没有被垃圾回收?不能是 DataTable 对象。
  • 显示CheckRecord的代码
  • @MartinLiversage 是的,但这并不意味着它会立即被收集。 AFAIK 无法保证对象何时会被 GC'd,GC 只会在下一次扫描时清除“孤立”对象,并且通常仅在需要重新声明 RAM 时触发。因此,它有可能在不需要的时候一直存在(我只是在猜测,我可能是错的)。

标签: .net multithreading winforms


【解决方案1】:

根据所提供的信息,无法回答您的问题。但是,要解决内存泄漏问题,您有几个选择:

  • 如果删除线程执行的代码,内存使用量增加会消失吗?如果没有,那么您必须在代码中的其他地方寻找泄漏。

  • 很可能泄漏不是托管内存,因为它是垃圾收集的。您可以通过监视性能计数器 .NET CLR Memory -> # Bytes in all Heaps 来验证这一点。如果此计数器在您的程序运行时显着增加,则您正在“泄漏”托管内存,因为您有一些活动数据结构不断增长,但不符合垃圾回收条件。

  • 假设您已经排除了受管理的“泄漏”,那么您将不得不寻找未受管理的泄漏。您是否编码调用了一些需要您清理的互操作 API?在您的代码中,唯一的可能性似乎是CheckRecord,您应该检查它以了解这是否是泄漏的来源。

查看您的代码,您似乎有错误或有错字:

public void Check() {
  bool isUpdate = false;
  while (isUpdate) {
    ...
  }
}

因为isUpdatefalse,所以永远不会进入while 循环,Check 将立即返回并终止线程。

【讨论】:

    【解决方案2】:

    您忘记在GetData() 返回的DataTable 上调用Dispose()。这是一个很好的答案,说明您为什么需要致电Dispose()

    Do I need to call Dispose() on managed objects?

    【讨论】:

    【解决方案3】:

    问题是您没有处理由创建的实例

    ss=temp.CreateChannel();
    

    因为创建的实例实现了 IDisposable 接口,所以您应该(必须)在不需要该实例时立即调用 Dispose() 方法。你可以阅读更多here

    特别注意using 关键字,以帮助您处置您的实例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-07
      • 2016-10-24
      • 1970-01-01
      • 2021-05-02
      • 2015-05-25
      • 2014-09-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多