识别内存泄漏

时间:2013-03-29 06:02:11

标签: c# .net memory-leaks ants

我想我的一个C#可执行文件(它是一个控制台应用程序)有严重的内存泄漏。内存大小不断增加和超时我需要重新启动应用程序以降低内存使用率。我正在使用FileSystemWatcher,然后当文件可用时,将其转换为utf-8并转发它。然后写入控制台,此时处理文件。所以它每次处理时都会写入控制台。

我正在使用Ants内存分析器,并且在开始使用它时非常新鲜。我无法弄清楚它。当我拍摄内存快照时,它会显示我:

namespace:System,Classname:byte [] ---每次处理文件并在控制台上显示它(40,000字节)时都会增加,并且永远不会返回。

这是否正确。

更新

class Class1
{
    private static FileSystemWatcher watcher = new FileSystemWatcher();

    public static void Main()
    {
        WatchFile();
        Console.ReadLine();
    }

    private static void WatchFile()
    {
        watcher.Path = @"N:\";
        watcher.NotifyFilter = NotifyFilters.LastWrite;
        watcher.Filter = "*.xml";
        watcher.Changed += new FileSystemEventHandler(convert);
        watcher.Error += new ErrorEventHandler(WatcherError);
        watcher.EnableRaisingEvents = true;

        Console.WriteLine("Press \'q\' to quit.");

        while (Console.Read() != 'q');
    }

    public static string CrL = "\r\n";

    private static object lockObject = new object();

    private static void convert(object source, FileSystemEventArgs f)
    {
       string FileName;
       FileName = f.FullPath;

       string destinationFile = @"F:\test.xml";

       Thread.Sleep(2000);
       if (!Monitor.TryEnter(lockObject))
       {
           return;
       }
       try
       {
           watcher.EnableRaisingEvents = false;
           Thread.Sleep(2000);

           var doc = new XmlDocument();
           doc.Load(FileName);

           XmlWriterSettings settings = new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true };

           using (var writer = XmlWriter.Create(destinationFile, settings))
           {
               doc.Save(writer);
           }

           Console.WriteLine("File Copied" + "  " + DateTime.Now.ToString("HH:mm:ss tt")); 
           Console.WriteLine("Press \'q\' to quit."); 
           Console.Write(CrL);
       }
       catch (Exception e)
       {
           Console.WriteLine("The process failed: {0}", e.ToString());
       }
       finally
       {
           Monitor.Exit(lockObject);
           watcher.EnableRaisingEvents = true;
           GC.Collect();
           GC.WaitForPendingFinalizers();
           GC.Collect();
       }
    }

    private class Utf8StringWriter : StringWriter
    {
        public override Encoding Encoding { get { return Encoding.UTF8; } }
    }

    private static void WatcherError(object source, ErrorEventArgs e)
    {
        Exception watchException = e.GetException();
        watcher = new FileSystemWatcher();
        while (!watcher.EnableRaisingEvents)
        {
            try
            {
                WatchFile();
                Console.WriteLine("I'm Back!!");
            }
            catch
            {
                Thread.Sleep(2000);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:2)

试试这样:

var doc = new XmlDocument();
doc.Load(FileName);

XmlWriterSettings settings = new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true };

using (var writer = XmlWriter.Create(destinationFile, settings))
{
    doc.Save(writer);
}
doc = null;

如果您未将doc设置为null,GC可能会将其视为活动参考,而不是释放内存。 GC有自己的垃圾收集逻辑,强制完整的垃圾收集不是最佳实践(Best Practice for Forcing Garbage Collection in C#)。

另外,我不相信你有内存泄漏;似乎GC没有被触发释放内存。当你说内存不断增加时,你的意思是什么?当你觉得需要把它带回来时它能达到什么水平?

修改

有关阅读XML文件的选项,请参阅此链接:Deciding on when to use XmlDocument vs XmlReader

使用非常大的XML文件时,可能会在大对象堆(LOH)上分配XMLDocuments,从而导致LOH中出现碎片并导致OutOfMemory异常。

那时

XMLReader可能更适合你。

答案 1 :(得分:2)

此处类似的问题 - Memory leak while using Threads

根据我对解决方案的理解,写入Console并使用Thread.Sleep是个问题。

此外,也许适用(或不适用) - http://support.microsoft.com/kb/2628838

从此处下载修补程序(Framework 4.0的可靠性更新2)文件 - http://support.microsoft.com/kb/2600217