内存泄漏,文件正在被另一个进程异常使用

时间:2013-01-16 04:09:18

标签: c# .net memory-leaks exception-handling filesystemwatcher

这个应用程序似乎吃了很多内存。也许我没有正确管理内存。有些人可以找出需要优化的代码。其次,文件复制不正常。它有时抛出一个异常,无法访问另一个进程正在使用的文件,这个异常被抛出到监视文件夹和我正在复制的目标文件夹的两端。让我简要介绍一下我在这里要实现的目标。

我有一个系统可以给我一个ansi格式的xml文件。这个文件可能会定期更新,可能每3-4分钟一次甚至10-20秒。现在我正在看这个文件夹,一旦它被更改我将其转换为UTF-8并通过sftp将其复制到另一个服务器。此sftp文件夹映射在发生转换的同一台计算机上。所以我面临的问题是它抛出的异常,无法访问另一个进程正在使用的文件,一段时间后这个被清除了。甚至是内存异常,即系统内存不足。它也在泄漏记忆。几小时后,启动时间为5k,内存使用量达到1.2gb。现在我需要运行其中3个类似程序,观看3个不同的文件夹。我的问题的任何线索?

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

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

        private static void WatchFile()
        {
            watcher.Path = @"c:\test";
            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.");
            Console.WriteLine("Press \'q\' to quit.");
            while (Console.Read() != 'q') ;
        }

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

        private static void convert(object source, FileSystemEventArgs f)
        {
           string FileName = f.FullPath;
           string destinationFile = @"z:\xml\test.xml";

           Thread.Sleep(2000);
           try
           {
                watcher.EnableRaisingEvents = false;
                Encoding utf8 = new UTF8Encoding(false);
                Encoding ansi = Encoding.GetEncoding(1256);
                Thread.Sleep(2000);

                string xml = File.ReadAllText(FileName, ansi);
                XDocument xmlDoc = XDocument.Parse(xml);
                File.WriteAllText(FileName, @"<?xml version=""1.0"" encoding=""utf-8""?>" + xmlDoc.ToString(), utf8);

                 if (File.Exists(destinationFile))
                     File.Delete(destinationFile);
                 File.Copy(FileName, destinationFile,true);
                 Console.WriteLine("File Copied"); // for troubleshoooting only
                 Console.Write(CrL);
            }
            catch (Exception e)
            {
                Console.WriteLine("The process failed: {0}", e.ToString());
            }
            finally
            {
                watcher.EnableRaisingEvents = true;
            }
        }

        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);
                }
            }
        }
    }  
}

1 个答案:

答案 0 :(得分:2)

每次收到错误消息时,都会再次致电WatchFile(),这会将convertWatcherError方法添加到ChangedError再次调用列表。这可以解释缓慢的内存泄漏。委托调用列表不断增长。

因为事件是在池线程上引发的,所以您的代码可以同时处理多个已更改的事件。

您的错误处理程序应该只重新启用事件(即Watcher.EnableRaisingEvents = true;)当然不应该再次添加事件处理程序。

您还需要使用convert方法同步访问权限。你可以用锁来做,但可能更好的想法是使用Monitor.TryEnter,如下所示:

private static object lockObject = new Object();
private static void convert(object source, FileSystemEventArgs f)
{
    if (!Monitor.TryEnter(lockObject))
    {
        // unable to get lock, return.
        return;
    }
    try
    {
        // do stuff here
    }
    finally
    {
        Monitor.Exit(lockObject);
    }