0

このアプリケーションは大量のメモリを消費しているようです。メモリを適切に管理していない可能性があります。どのコードを最適化する必要があるかを理解してください。次に、ファイルのコピーが正しく機能していません。例外がスローされることがあり、別のプロセスで使用されているファイルにアクセスできません。この例外は、監視フォルダーとコピー先のフォルダーの両端でスローされます。ここで私が達成しようとしていることの簡単な説明をさせてください。

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

1 に答える 1

2

エラーが発生するたびに再度呼び出します。これにより、 andメソッドがand呼び出しリストに再度WatchFile()追加されます。それは遅いメモリリークを説明するでしょう。デリゲート呼び出しリストは増え続けています。convertWatcherErrorChangedError

イベントはプール スレッドで発生するため、コードが複数の変更されたイベントを同時に処理する可能性があります。

エラー ハンドラーは、イベントを再度有効にする必要があります (つまり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);
    }
于 2013-01-16T04:38:07.247 に答える