这个While Foreach循环会导致托管内存泄漏吗



我在这里阅读@suproct的帖子https://stackoverflow.com/a/10317035我有一个关于以下的问题:

需要注意的是,即使是只与100%托管对象交互的对象也可以做需要清理的事情(并且应该使用IDisposable)。例如,附加到集合的"已修改"事件的IEnumerator在不再需要时需要将其自身分离。否则,除非枚举器使用一些复杂的技巧,否则只要集合在范围内,枚举器就永远不会被垃圾收集。如果集合被枚举一百万次,那么一百万个枚举器将附加到其事件处理程序。

目前,我的代码中有一个非常非常缓慢的内存泄漏,我很难将其隔离(至少需要12个小时才能注意到私人内存的趋势,至少需要3天才能引发OutOfMemoryException)。我认为这可能与@ssupercat提到的内部订阅事件有关,除了我处理的是C#而不是VB。在生产代码中,如果while循环退出,GC会清理内存,但在此之前不会。

在下面的代码中,是否有任何事件处理程序在幕后被订阅

这两个循环中是否有任何内容看起来像管理泄漏

Directory.EnumerateFiles()是否具有奇怪的内存使用行为

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DoForeachWhile_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press any key to begin. Press Escape to stop the program.");
            ConsoleKeyInfo KeyPressed = Console.ReadKey();
            while (KeyPressed.Key != ConsoleKey.Escape)
            {
                IEnumerable<string> SomeIteration = Directory.EnumerateFiles(@"C:"); // new List<string>() { "1", "2", "3", "4", "5" };
                foreach (var StringItem in SomeIteration)
                {
                    Console.WriteLine(StringItem);
                }
                //Thread.Sleep(10);
                Console.Clear();
                if (Console.KeyAvailable)
                    KeyPressed = Console.ReadKey(true);
            }
            Console.WriteLine("Press any key to exit the program.");
            Console.ReadKey();
        }
    }
}

在运行示例代码一天后,没有出现任何泄漏。

正如评论所说,我也不认为循环中存在内存泄漏。

但是这部分呢:如果RunningOTS.StartWork(...)抛出异常怎么办?然后您是否应该调用RunningOTS.EndWork(...)并传递一个可能无效的WorkStartHandle

通常我会写一个像这样的块

try
{
    WorkStartHandle =
        RunningOTS.StartWork(p_waitForStartAcknowledge: true);
    // do {  } while ( )
    RunningOTS.EndWork(WorkStartHandle);
}
finally
{
    Log
        .FormattedLine(MessageScope.Nests,
        "{0} :: RunToken {1}", NestID, RunningOTS);
}

然而,这可能不适用于您,因为我不知道您是否会在do while中引发异常。可能是您得到了一个由RunningOTS.StartWork(...)以外的行引发的异常,并且您确实需要调用RunningOTS.EndWork(...)

因此,我最好的建议是以某种方式测试WorkStartHandlefinally块中是否有效。假设这是一个像许多其他手柄一样的手柄,

if (WorkStartHandle >= 0) // valid handle?
    RunningOTS.EndWork(WorkStartHandle)

可能会起作用。

最新更新