【问题标题】:Memory leak in c# Windows service?c# Windows 服务中的内存泄漏?
【发布时间】:2014-04-19 08:25:16
【问题描述】:

我有一个 Windows 服务,它会定期检查数据库中的新记录并在新线程中处理每条记录(最多可能需要 10 分钟)。当服务在启动后立即空闲时,它需要 4 MB 的 RAM。当它开始处理第一条记录时,它会上升到 70+ MB 并且即使在线程完成后也保持在那里(我想这没关系,因为很快就会再次需要这个内存)。然后在下一个请求中,它会从 70 MB 增加到大约 100 MB,并且在线程完成后也停留在那里。 所以我的问题是这样的事情是否存在内存泄漏:

public partial class MyWinService : ServiceBase
{
    DBService service;
    IEnumerable<long> unfinishedRequests;
    List<long> activeRequests;

    protected override void OnStart(string[] args)
    {
        System.Timers.Timer timer1 = new System.Timers.Timer(60000);
        timer1.Elapsed += Timer_Tick;
        timer1.Start();
        service = new DBService();
        activeRequests = new List<long>();
    }

    private void Timer_Tick(object sender, System.Timers.ElapsedEventArgs e)
    {
            unfinishedRequests = service.GetUnfinishedRequests();
            foreach (var req in unfinishedRequests)
            {
                new Thread(delegate() { ProcessRequest(req); }).Start();
            }
    }

    private void ProcessRequest(long requestID)
    {
        activeRequests.Add(requestID);
        // Lots of webservice calls, XML->XSLT->HTML->PDF, byte arrays, database INSERTs & UPDATEs etc.
        activeRequests.Remove(requestID);
    }
}

ProcessRequest() 方法中创建的所有对象不应该在线程完成后销毁吗?如果程序在第一个线程之后已经有 100 MB 内存,为什么还要要求更多(在我的测试中,输入数据是相同的,所以我认为两个线程应该使用相同数量的内存)。

【问题讨论】:

    标签: c# .net multithreading memory-leaks windows-services


    【解决方案1】:

    不了解ProcessRequest函数的更多细节,很难回答你的问题。

    您可以尝试使用任何可用的内存分析器自行查找内存泄漏问题

    ants-memory-profiler

    What Are Some Good .NET Profilers?

    【讨论】:

      【解决方案2】:

      至少有两件事可能表现为内存泄漏。

      首先,您的activeRequests 列表会不断添加,但不会调整大小。尽管您从列表中删除项目,但分配用于保存这些项目的内存永远不会回收。如果您将一百万个项目添加到列表中,然后将它们全部删除,则仍会分配存储这些项目的底层内存。

      不过,您的列表必须非常大(大约 400 万个项目)才能构成 30 兆字节。

      您说您的计时器滴答方法最多可能需要 10 分钟才能完成。你有一个问题,因为虽然计时器滴答会很快完成,但它创建的线程可能需要很长时间才能执行。一分钟后,另一个计时器会出现并排队更多线程。您在这里对线程没有限制,因此如果有一千个未完成的请求,您将处理 1,000 个线程。这绝对不是什么好事,这样很可能会耗尽内存。

      您应该考虑在该循环中使用Parallel.ForEach。例如:

      Parallel.ForEach(unfinishedRequests, req => ProcessRequest(req));
      

      这将限制并发线程的数量,从而防止线程过多而导致内存不足或由于任务切换过多而导致系统变慢。

      我不知道您所说的内存泄漏是否实际上是内存泄漏。如果您使用任务管理器来确定进程正在使用的内存量,那么您并不是在测量实际的内存使用情况。除非您真的严重泄漏,否则任务管理器对于查找内存泄漏毫无用处。在 SO 中搜索有关 C# 中内存泄漏检测的信息以获取一些想法。

      【讨论】:

        【解决方案3】:

        原来我过于依赖静态辅助类。一旦我将静态更改为实例,内存消耗就会显着减少,并且 GC 也能够释放更多内存

        【讨论】:

        • +1 不错的 anz,需要在我的应用中重新实施
        • 非常有趣,遇到了同样的问题
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-30
        • 2018-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-18
        相关资源
        最近更新 更多