2009-11-12 1 views
2

У меня есть небольшая проблема с управлением памятью в службе Windows, написанной на C# (фреймворк 3.5, visual studio 2008).C# проблема обслуживания окон с памятью (утечка памяти?)

Служба работает нормально, с таймером и вызовом Проведите огонь каждые три минуты. Следовательно, память в диспетчере задач Windows медленно растет при каждом запуске таймера.

У вас есть идея решить эту проблему?

Чтобы упростить задачу, ниже очень простой код, который Экспонаты с той же проблемой:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceProcess; 
using System.Text; 
using System.Threading; 
using System.IO; 

namespace svcTest 
{ 
public partial class svcTest : ServiceBase 
{ 

    private Timer tmr; 
    private TimerCallback tmrCallBack; 

    public svcTest() 
    { 
     InitializeComponent(); 
    } 

    protected override void OnStart(string[] args) 
    { 
     FileStream fs = new FileStream(@"c:\svclog.txt", FileMode.OpenOrCreate, FileAccess.Write); 
     StreamWriter m_streamWriter = new StreamWriter(fs); 
     m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
     m_streamWriter.WriteLine("Service Started on " + DateTime.Now.ToLongDateString() + " at " + DateTime.Now.ToLongTimeString()); 
     m_streamWriter.WriteLine(" *----------------*"); 
     m_streamWriter.Flush(); 
     m_streamWriter.Close(); 

     tmrCallBack = new TimerCallback(goEXE); 
     tmr = new Timer(tmrCallBack, null, 0, 1000 * 60 * 1/2); 
    } 

    protected override void OnStop() 
    { 
     FileStream fs = new FileStream(@"c:\svclog.txt", FileMode.OpenOrCreate, FileAccess.Write); 
     StreamWriter m_streamWriter = new StreamWriter(fs); 
     m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
     m_streamWriter.WriteLine("Service Stopped on " + DateTime.Now.ToLongDateString() + " at " + DateTime.Now.ToLongTimeString()); 
     m_streamWriter.WriteLine(" *----------------*"); 
     m_streamWriter.Flush(); 
     m_streamWriter.Close(); 

     tmr.Dispose(); 
    } 

    private void goEXE(Object state) 
    { 
     Console.WriteLine(DateTime.Now.ToString()); 

     FileStream fs = new FileStream(@"c:\svclog.txt", FileMode.OpenOrCreate, FileAccess.Write); 
     StreamWriter m_streamWriter = new StreamWriter(fs); 
     m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
     m_streamWriter.WriteLine("Service running on " + DateTime.Now.ToLongDateString() + " at " + DateTime.Now.ToLongTimeString()); 
     m_streamWriter.WriteLine(" *----------------*"); 
     m_streamWriter.Flush(); 
     m_streamWriter.Close(); 

    } 

    } 
} 

Любая помощь будет оценен по достоинству!

Stefano

ответ

6

Вы не утилизацией вашего FileStream. Сборщик мусора может позвонить вам Dispose(), но он не является детерминированным (т. Е. Вы не знаете, когда/если это произойдет). Вероятно, здесь решено не беспокоиться. В результате практики рекомендуется рассмотреть обертывание ничего, реализующий IDisposable в using заявлении:

using (FileStream fs = new FileStream(@"c:\svclog.txt", FileMode.OpenOrCreate, FileAccess.Write) 
{ 
    using (using (StreamWriter m_streamWriter = new StreamWriter(fs))) 
    { 
     m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
     m_streamWriter.WriteLine("Service Started on " + DateTime.Now.ToLongDateString() + " at " + DateTime.Now.ToLongTimeString()); 
     m_streamWriter.WriteLine(" *----------------*"); 
    } 
} 

Для поддержания и DRY причины, вы должны также рассмотреть вопрос рефакторинга кода записи файла в отдельный метод:

private void Log(string message) 
{ 
    using (FileStream fs = new FileStream(@"c:\svclog.txt", FileMode.OpenOrCreate, FileAccess.Write) 
    { 
     using (using (StreamWriter m_streamWriter = new StreamWriter(fs))) 
     { 
      m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
      m_streamWriter.WriteLine(message + " " + DateTime.Now.ToLongDateString() + " at " + DateTime.Now.ToLongTimeString()); 
      m_streamWriter.WriteLine(" *----------------*"); 
     } 
    } 
} 

protected override void OnStart(string[] args) 
{ 
    Log("Service Started"); 

    tmrCallBack = new TimerCallback(goEXE); 
    tmr = new Timer(tmrCallBack, null, 0, 1000 * 60 * 1/2); 
} 

protected override void OnStop() 
{ 
    Log("Service Stopped"); 

    tmr.Dispose(); 
} 

private void goEXE(Object state) 
{ 
    Console.WriteLine(DateTime.Now.ToString()); 

    Log("Service running"); 
} 
+0

частная пустота goEXE (состояние объекта) { ... тот же код, как описано выше ... m_streamWriter.Dispose(); fs.Dispose(); } – stexcec

+0

Ницца просто исправил утечку памяти с помощью StreamWriter! Спасибо! – Moss

+0

Почему вложенное использование в StreamWriter? Я искал, но не вижу ответа. – GaTechThomas

0

Я бы предположил, что ваш файл продолжает расти, так как вы добавляете новые строки до конца, и, таким образом, потоковый блок потребляет больше памяти.

Я предпочел бы создать один создатель потока при запуске программы вместо того, чтобы делать это при обратном вызове. Но тогда у вас будет файл, заблокированный .

1

Кроме того, сборка мусора .NET запускается при попадании определенных оптимальных параметров. Если система недостаточно работает в памяти, она может решить, что запуск GC.Collect слишком дорог, и, таким образом, ваши объекты без ссылки, но все еще в памяти будут продолжать оставаться таким образом.

0
public class Logger : IDisposable 
{ 
    public void Log(string message) 
    { 
     using (FileStream fs = new FileStream(@"c:\svclog.txt", FileMode.OpenOrCreate, FileAccess.Write) 
     { 
      using (using (StreamWriter m_streamWriter = new StreamWriter(fs))) 
      { 
       m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
       m_streamWriter.WriteLine(message + " " + DateTime.Now.ToLongDateString() + " at " + DateTime.Now.ToLongTimeString()); 
       m_streamWriter.WriteLine(" *----------------*"); 
      } 
     } 
    } 
    public void Dispose() 
    { 
     GC.SuppressFinalize(this); 

    } 
} 
0

Использование File.AppendAllText(path, content); Лучшее, оно будет обрабатывать все утечки памяти.