2

C# 実行可能ファイルの 1 つ (コンソール アプリケーション) で深刻なメモリ リークが発生していると思います。メモリ サイズが増え続けているため、アプリケーションを再起動してメモリ使用量を下げる必要があります。私は 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);
            }
        }
    }
}
4

2 に答える 2

2

ここで同様の質問 - スレッド使用中のメモリ リーク

ソリューションから私が理解していることから、コンソールへの書き込みと Thread.Sleep の使用が問題でした。

また、おそらく該当する(または該当しない)- http://support.microsoft.com/kb/2628838

ここから修正プログラム (フレームワーク 4.0 の信頼性更新プログラム 2) ファイルをダウンロードします。http://support.microsoft.com/kb/2600217

于 2013-03-29T07:01:07.950 に答える
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 にはガベージ コレクション用の独自のロジックがあり、完全なガベージ コレクションを強制することはベスト プラクティスではありません ( C# でガベージ コレクションを強制するためのベスト プラクティス)。

また、メモリリークがあるとは思いません。メモリを解放するために GC がトリガーされていないようです。メモリが増加し続けるとはどういう意味ですか? それを元に戻す必要があると感じたとき、それはどのレベルに達しますか?

編集

XML ファイルの読み取りに関するオプションについては、このリンクを参照してください: Deciding on when to use XmlDocument vs XmlReader

非常に大きな XML ファイルを操作する場合、大きなオブジェクト ヒープ (LOH) に割り当てられた XMLDocuments を取得する可能性があり、LOH で断片化が発生し、OutOfMemory 例外が発生する可能性があります。

XMLReaderその場合は、こちらの方が適しているかもしれません。

于 2013-03-29T06:42:23.373 に答える