【问题标题】:GC.Collect() not working when run once a day vs when run continuouslyGC.Collect() 在每天运行一次与连续运行时不起作用
【发布时间】:2020-06-27 23:46:51
【问题描述】:

我有一个 Windows 服务。有2个项目;服务项目 (C#),其中包含具有所有基于计时器的代码(OnStart、OnStop、Timer_Elapsed 等)和配置文件的服务类。另一个项目 (VB) 有关于服务在 Manager 类中实际执行的代码。

此 Windows 服务存在内存泄漏,内存使用量的增长率约为 50 MB/天。在一个月内,它的内存使用量几乎达到了 1.5 GB。

从长远来看,我的公司计划实施 IDisposable,但作为临时解决方案,我们决定使用 GC.Collect()。因此,我在 timer_elapsed() 中添加了 GC.Collect(),自 poll_interval = 3 后每 3 秒调用一次。我还将一些未实现 IDisposable 的对象设置为 null/Nothing。

int counter = 0;

private void Timer_Elapsed()
{
    // create instance of Manager.cs
    try
    {
        // do something
    }
    catch (Exception ex)
    {
        // handle errors
    }
    finally
    {
        Process currentProcess = Process.GetCurrentProcess();
        Logger logger = LogManager.GetCurrentClassLogger();
        logger.Debug("Working Set " + currentProcess.WorkingSet64);

        counter += 1;
        if (counter == counterThreshold)
        {
            counter = 0;
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
            GC.WaitForPendingFinalizers();
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
            logger.Debug("GC");
            logger.Debug("Gen 0: " + GC.CollectionCount(0));
            logger.Debug("Gen 1: " + GC.CollectionCount(1));
            logger.Debug("Gen 2: " + GC.CollectionCount(2));
        }

        currentProcess.Dispose();
        logger = null;

        // set objects to null

        _timer.Start();
    }
}

当 counterThreshold 设置为 1 时,内存使用量始终保持在 ~28 MB。当它设置为 10 时,使用量保持在 ~28 MB +/- 0.5 MB。当设置为 75 时(因为 poll_interval = 3 时,timer_elapsed 调用了 20 次/分钟,所以设置 counterThreshold 为 75 意味着每 3.75 分钟调用一次 GC.Collect()),我可以看到 GC.Collect() 似乎没有会产生很大的不同。

12:53:24|SVC.Service1|Working Set 27172864
12:53:27|SVC.Service1|Working Set 27762688
12:53:30|SVC.Service1|Working Set 27844608
12:53:33|SVC.Service1|Working Set 27926528
12:53:36|SVC.Service1|Working Set 28012544
12:53:39|SVC.Service1|Working Set 28094464
12:53:42|SVC.Service1|Working Set 28176384
12:53:45|SVC.Service1|Working Set 28258304
12:53:48|SVC.Service1|Working Set 28344320
12:53:52|SVC.Service1|Working Set 28426240
12:53:55|SVC.Service1|Working Set 28516352
12:53:58|SVC.Service1|Working Set 28598272
12:54:01|SVC.Service1|Working Set 28676096
12:54:04|SVC.Service1|Working Set 28762112
12:54:07|SVC.Service1|Working Set 28839936
12:54:10|SVC.Service1|Working Set 28921856
12:54:13|SVC.Service1|Working Set 29003776
12:54:16|SVC.Service1|Working Set 29089792
12:54:19|SVC.Service1|Working Set 29179904
12:54:22|SVC.Service1|Working Set 29257728
12:54:25|SVC.Service1|Working Set 29343744
12:54:28|SVC.Service1|Working Set 29425664
12:54:31|SVC.Service1|Working Set 29503488
12:54:34|SVC.Service1|Working Set 29536256
12:54:37|SVC.Service1|Working Set 29618176
12:54:40|SVC.Service1|Working Set 29696000
12:54:43|SVC.Service1|Working Set 29777920
12:54:46|SVC.Service1|Working Set 29859840
12:54:49|SVC.Service1|Working Set 29945856
12:54:52|SVC.Service1|Working Set 30081024
12:54:55|SVC.Service1|Working Set 30162944
12:54:58|SVC.Service1|Working Set 30248960
12:55:01|SVC.Service1|Working Set 30330880
12:55:04|SVC.Service1|Working Set 30416896
12:55:07|SVC.Service1|Working Set 30511104
12:55:10|SVC.Service1|Working Set 30597120
12:55:13|SVC.Service1|Working Set 30674944
12:55:16|SVC.Service1|Working Set 30756864
12:55:19|SVC.Service1|Working Set 30842880
12:55:22|SVC.Service1|Working Set 30924800
12:55:25|SVC.Service1|Working Set 31002624
12:55:28|SVC.Service1|Working Set 31064064
12:55:31|SVC.Service1|Working Set 31158272
12:55:34|SVC.Service1|Working Set 31240192
12:55:37|SVC.Service1|Working Set 31318016
12:55:40|SVC.Service1|Working Set 31395840
12:55:43|SVC.Service1|Working Set 31547392
12:55:46|SVC.Service1|Working Set 31543296
12:55:49|SVC.Service1|Working Set 31543296
12:55:53|SVC.Service1|Working Set 31547392
12:55:56|SVC.Service1|Working Set 31543296
12:55:59|SVC.Service1|Working Set 31490048
12:56:02|SVC.Service1|Working Set 31494144
12:56:05|SVC.Service1|Working Set 31490048
12:56:08|SVC.Service1|Working Set 31494144
12:56:11|SVC.Service1|Working Set 31494144
12:56:14|SVC.Service1|Working Set 31494144
12:56:17|SVC.Service1|Working Set 31490048
12:56:20|SVC.Service1|Working Set 31494144
12:56:23|SVC.Service1|Working Set 31543296
12:56:26|SVC.Service1|Working Set 31547392
12:56:29|SVC.Service1|Working Set 31547392
12:56:32|SVC.Service1|Working Set 31547392
12:56:35|SVC.Service1|Working Set 31551488
12:56:38|SVC.Service1|Working Set 31543296
12:56:41|SVC.Service1|Working Set 31543296
12:56:44|SVC.Service1|Working Set 31543296
12:56:47|SVC.Service1|Working Set 31547392
12:56:50|SVC.Service1|Working Set 31543296
12:56:53|SVC.Service1|Working Set 31543296
12:56:56|SVC.Service1|Working Set 31547392
12:56:59|SVC.Service1|Working Set 31547392
12:57:02|SVC.Service1|Working Set 31547392
12:57:05|SVC.Service1|Working Set 31547392
12:57:08|SVC.Service1|Working Set 31547392
12:57:08|SVC.Service1|GC
12:57:08|SVC.Service1|Gen 0: 3
12:57:08|SVC.Service1|Gen 1: 2
12:57:08|SVC.Service1|Gen 2: 2
12:57:11|SVC.Service1|Working Set 31956992
12:57:14|SVC.Service1|Working Set 31956992
12:57:17|SVC.Service1|Working Set 31956992
12:57:20|SVC.Service1|Working Set 31952896
12:57:23|SVC.Service1|Working Set 31952896
12:57:26|SVC.Service1|Working Set 31956992
12:57:29|SVC.Service1|Working Set 31899648
12:57:32|SVC.Service1|Working Set 31903744
12:57:35|SVC.Service1|Working Set 31899648
12:57:38|SVC.Service1|Working Set 31903744
12:57:41|SVC.Service1|Working Set 31903744
12:57:44|SVC.Service1|Working Set 31903744
12:57:47|SVC.Service1|Working Set 31903744
12:57:50|SVC.Service1|Working Set 31903744
12:57:53|SVC.Service1|Working Set 31899648
12:57:56|SVC.Service1|Working Set 31903744
12:57:59|SVC.Service1|Working Set 31899648
12:58:02|SVC.Service1|Working Set 31903744
12:58:05|SVC.Service1|Working Set 31903744
12:58:08|SVC.Service1|Working Set 31903744
12:58:11|SVC.Service1|Working Set 31903744
12:58:14|SVC.Service1|Working Set 31903744
12:58:17|SVC.Service1|Working Set 31899648
12:58:20|SVC.Service1|Working Set 31899648
12:58:23|SVC.Service1|Working Set 31903744
12:58:26|SVC.Service1|Working Set 31903744
12:58:29|SVC.Service1|Working Set 31903744
12:58:32|SVC.Service1|Working Set 31899648
12:58:35|SVC.Service1|Working Set 31899648
12:58:38|SVC.Service1|Working Set 31903744
12:58:42|SVC.Service1|Working Set 31903744
12:58:45|SVC.Service1|Working Set 31899648
12:58:48|SVC.Service1|Working Set 31903744
12:58:51|SVC.Service1|Working Set 31899648
12:58:54|SVC.Service1|Working Set 31903744
12:58:57|SVC.Service1|Working Set 31899648
12:59:00|SVC.Service1|Working Set 31903744
12:59:03|SVC.Service1|Working Set 31903744
12:59:06|SVC.Service1|Working Set 31903744
12:59:09|SVC.Service1|Working Set 31899648
12:59:12|SVC.Service1|Working Set 31903744
12:59:15|SVC.Service1|Working Set 31899648
12:59:18|SVC.Service1|Working Set 31907840
12:59:21|SVC.Service1|Working Set 31899648
12:59:24|SVC.Service1|Working Set 31899648
12:59:27|SVC.Service1|Working Set 32026624
12:59:30|SVC.Service1|Working Set 32030720
12:59:33|SVC.Service1|Working Set 32026624
12:59:36|SVC.Service1|Working Set 32030720
12:59:39|SVC.Service1|Working Set 32030720
12:59:42|SVC.Service1|Working Set 32030720
12:59:45|SVC.Service1|Working Set 32071680
12:59:48|SVC.Service1|Working Set 32067584
12:59:51|SVC.Service1|Working Set 32104448
12:59:54|SVC.Service1|Working Set 32108544
12:59:57|SVC.Service1|Working Set 32108544
13:00:00|SVC.Service1|Working Set 32112640
13:00:03|SVC.Service1|Working Set 32124928
13:00:06|SVC.Service1|Working Set 32202752
13:00:09|SVC.Service1|Working Set 32280576
13:00:12|SVC.Service1|Working Set 32362496
13:00:15|SVC.Service1|Working Set 32473088
13:00:18|SVC.Service1|Working Set 32559104
13:00:21|SVC.Service1|Working Set 32641024
13:00:24|SVC.Service1|Working Set 32722944
13:00:27|SVC.Service1|Working Set 32747520
13:00:30|SVC.Service1|Working Set 32747520
13:00:33|SVC.Service1|Working Set 32690176
13:00:36|SVC.Service1|Working Set 32632832
13:00:39|SVC.Service1|Working Set 32636928
13:00:42|SVC.Service1|Working Set 32628736
13:00:45|SVC.Service1|Working Set 32665600
13:00:48|SVC.Service1|Working Set 32669696
13:00:51|SVC.Service1|Working Set 32669696
13:00:54|SVC.Service1|Working Set 32669696
13:00:54|SVC.Service1|GC
13:00:54|SVC.Service1|Gen 0: 6
13:00:54|SVC.Service1|Gen 1: 4
13:00:54|SVC.Service1|Gen 2: 4
13:00:57|SVC.Service1|Working Set 32673792
13:01:00|SVC.Service1|Working Set 32677888
13:01:03|SVC.Service1|Working Set 32673792
13:01:06|SVC.Service1|Working Set 32677888
13:01:09|SVC.Service1|Working Set 32677888
13:01:12|SVC.Service1|Working Set 32673792
13:01:15|SVC.Service1|Working Set 32677888
13:01:18|SVC.Service1|Working Set 32677888
13:01:21|SVC.Service1|Working Set 32673792
13:01:24|SVC.Service1|Working Set 32673792
13:01:27|SVC.Service1|Working Set 32673792
13:01:30|SVC.Service1|Working Set 32673792
13:01:33|SVC.Service1|Working Set 32628736
13:01:36|SVC.Service1|Working Set 32632832
13:01:39|SVC.Service1|Working Set 32624640
13:01:42|SVC.Service1|Working Set 32628736
13:01:45|SVC.Service1|Working Set 32628736
13:01:48|SVC.Service1|Working Set 32628736
13:01:52|SVC.Service1|Working Set 32628736
13:01:55|SVC.Service1|Working Set 32628736

当 counterThreshold 设置为 28800(即每天调用 GC.Collect() 一次)时,内存使用量的增加仍然是每天约 50 MB,调用 GC.Collect() 似乎根本没有任何区别。

memory usage graph

每次调用 GC.Collect() 时,无论是连续调用还是每天调用一次,我都希望内存使用量下降到 ~28 MB。

  1. 当 counterThreshold 增加/当 counterThreshold = 28800 时,GC.Collect() 会发生什么?
  2. 为什么连续运行时有效,而每天运行一次时无效?
  3. 无论 counterThreshold 的值如何,我都可以使用 GC 做什么,以便每当我调用 GC.Collect() 时内存使用量下降到 ~28 MB?

【问题讨论】:

  • 让任务管理器显示一个喜欢的内存使用情况通常很痛苦......如果您真正解释您正在测量的内容(请参阅stackoverflow.com/questions/31096/…)以及为什么您希望工作集表现不同,这将有所帮助。
  • GC.Collect 不能解决内存泄漏问题。它不会破坏其他人活着/引用的对象。 GC.Collect 只收集给定代的对象。如果您认为您有一些可以立即收集的对象,例如已关闭的大位图,调用GC.Collect 会有所帮助。否则,GC.Collect 不会做太多事情。
  • 这不是我们处理疑似内存泄漏的方式,.net 不会主动将内存还给操作系统,调用 gc collect 也不会修复内存泄漏,也就是说读取内存使用情况是这样的徒劳的。您将学习如何使用内存分析器
  • @MichaelRandall 很有可能在 OP 的代码中实际上没有内存泄漏......他们只是不喜欢 GC 在认为没有必要时不运行。在 X64 上,GC 通常有太多空间来收集任何 50Mb/天的分配。整个问题可能是他们不喜欢显示的数字......但在这种情况下这不是必要的编程问题:)
  • 内存泄漏的性质与您期望 GC 解决的问题相反。它们是您认为 GC 应该收集但根本不能收集的对象,因为它们仍然是根目录。多次调用 Collect 永远不会修复泄漏。事实上,在大多数情况下,通过更快地进行生成提升应该弊大于利。您是否使用探查器确认了这些,包括存在泄漏?没有人,我不会开始接触这样的问题。

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


【解决方案1】:

从我在问题下的评论中复制:

GC.Collect 不能解决内存泄漏问题。它不会破坏其他人活着/引用的对象。 GC.Collect 只收集给定世代的对象。如果您认为您有一些可以立即收集的对象,例如已关闭的大位图,调用 GC.Collect 会有所帮助。否则,GC.Collect 不会做太多事情。

此外,垃圾收集在后台不断运行。调用GC.Collect 只会强制垃圾收集现在运行。如果没有什么可收集的,内存使用率不会下降。

每天一次不工作与连续运行可能是巧合,当每天调用一次 GC.Collect 时,没有什么可收集的,而连续运行会增加收集东西的机会。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 2014-08-14
    • 2012-12-28
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多