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

时间:2014-09-05 20:11:05

标签: c# memory-leaks foreach

我正在阅读@ supercat的帖子https://stackoverflow.com/a/10317035,我对以下内容有疑问:

  

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

我目前的代码中存在非常非常慢的内存泄漏,而且我有一段时间隔离它(需要至少12小时才能注意到私有内存中的趋势,至少需要3天时间全抛出之前会抛出一个OutOfMemoryException)。我认为它可能与@supercat提到的关于内部订阅事件的内容有关,除了我处理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();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

运行示例代码一天后没有泄漏。

答案 1 :(得分:0)

正如评论所说,我也认为你的循环中没有内存泄漏。

但是这一部分呢:如果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(...)

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

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

......可能有效。