【问题标题】:Windows Service Memory Usage IncreasesWindows 服务内存使用量增加
【发布时间】:2017-05-25 09:20:53
【问题描述】:

我有一个 Windows 服务正在执行 3 个预定的作业。首先是向员工发送电子邮件,了解他们的轮班时间。第二个是获取 Active Directory 信息并将其保存到本地数据库。最后一个是将活动目录照片保存到文件目录。

每个作业都在单独的线程上完成。计时器每 45 秒计时一次。除了服务的内存使用量稳步增加外,一切都运行良好。

您知道是什么原因造成的吗?

Thread[] thread;

protected override void OnStart(string[] args)
{
    timer = new System.Timers.Timer();
    timer.AutoReset = true;
    timer.Enabled = true;
    timer.Interval = 1000 * 45;
    timer.Start();
    timer.Elapsed += Timer_Elapsed;
    servisList = new List<IService>() { new ShiftNotification(), new     ActiveDirectoryService(), new DirectoryPhotos() };
    thread = new Thread[servisList.Count];
}

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    try
    {
        for (int i = 0; i < servisList.Count; i++)
        {
            if (thread[i] == null)
            {
                if (TimeControl.CheckTime(DateTime.Now, servisList.ElementAt(i).sProps))
                {
                    thread[i] = new System.Threading.Thread(new System.Threading.ThreadStart(servisList.ElementAt(i).NotifyUsers));
                    thread[i].Start();
                }
            }
            else
            {
                if (thread[i].ThreadState != System.Threading.ThreadState.Running)
                {
                    if (TimeControl.CheckTime(DateTime.Now, servisList.ElementAt(i).sProps))
                    {
                        thread[i] = new System.Threading.Thread(new System.Threading.ThreadStart(servisList.ElementAt(i).NotifyUsers));
                        thread[i].Start();
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
    }
}

【问题讨论】:

    标签: c# multithreading memory-leaks timer windows-services


    【解决方案1】:

    只是对此的一些想法

    1. ActiveDirectorySmcpClient(如果您不将其用于电子邮件,请纠正我)的使用意味着您正在处理非托管资源,您是否正确处理了这些类?您可能应该将客户端变量设置为静态字段,并在程序结束时处理它们。
    2. 这些行我不清楚:

      if (thread[i].ThreadState != System.Threading.ThreadState.Running)
      {
          if (TimeControl.CheckTime(DateTime.Now, servisList.ElementAt(i).sProps))
          {
              thread[i] = new System.Threading.Thread(new System.Threading.ThreadStart(servisList.ElementAt(i).NotifyUsers));
              thread[i].Start();
          }
      }
      

      Thread 也是非托管资源,因此,由于它正在实现 IDisposable,您应该在为数组条目分配新值之前处理前一个:thread[i].Dispose();

    3. 次要你为什么要使用全名,因为你已经添加了using System.Threading

    【讨论】:

    • 1) 你是对的。我正在使用 ActiveDirectory 和 SmtpClient 类。我不知道我必须处置这些物品。 2) 我有某些任务在单独的线程上运行。我通过 TimeControl 类控制它。此外,如果线程处于运行状态,我不想分配新值并启动它。 3)我的错!我从我的代码中删除了它。
    • 在 2 中,你是说我需要实现 IDisposable 吗?
    • 您可以覆盖其中一个表单的Dispose 处理程序,或者在关闭应用程序期间处理这些对象。仅仅实现IDisposable 是不够的——你必须清除你的资源。具体如何操作由您决定。
    • @SeckinCelik,如果可以选择大于 3.6 的 .Net 框架版本,请尝试使用具有长时间运行任务的 TPL
    • 这是一个 Windows 服务,因此它会一直运行,直到我停止它为止。我想在关闭之前处理处置对我来说不起作用。我会尝试TPL。
    【解决方案2】:

    AFAICT,如果没有关于您在 NotifyUsers 方法中所做的更具体的信息,就不可能回答这个问题。

    但即使在研究之前,我也会先用这个重新审视你所拥有的线程生成逻辑

    if (thread[i] == null)
    {
       // (code omitted)
    }
    else
    {
       // (code omitted)
    }
    

    我的意思是,首先尝试弄清楚您的服务是否最终会产生过多的工作线程(这是我的疯狂猜测,先验)。

    更具体地说,一旦/每次您使用 System.Threading.Thread,请始终将race condition 视为最先/最可能需要注意的问题之一。

    多线程绝非易事。但是plenty of resources 可以帮助您完成工作。

    '希望这会有所帮助。

    【讨论】:

    • 如果线程状态不是“正在运行”,则只有 3 个线程被创建并重新运行。每个线程大约需要 5 到 10 分钟才能完成。 NotifyUsers 方法正在获取大约 800 个 Active Directory 用户并在本地数据库上保存/更新。
    • @SeckinCelik :如果您确信没有创建太多线程,那么我会调查(通过内存分析)为什么他们从 AD 收集的任何数据(可能)没有' t 得到应有的垃圾收集,并且(可能)不断堆积到您的服务进程的内存中。一个好的做法是首先将 Windows 服务开发为独立的控制台应用程序,以简化调试和分析。
    • 更具体地说,需要注意的事项:变量和类类型字段的静态和运行时范围(例如,任何静态?和/或对象引用周期,使得太多实例仍然可以从 GC 根访问?等)
    • 一个您可能会觉得有用的资源:@​​987654323@
    猜你喜欢
    • 2021-12-08
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    • 2014-01-09
    • 1970-01-01
    • 2013-08-07
    相关资源
    最近更新 更多