C # Windows службы проблема с памятью (утечка памяти?) - PullRequest
2 голосов
/ 12 ноября 2009

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

Служба работает нормально, с Таймером и CallBack запускает процедуру каждые 3 минуты. Поэтому память в диспетчере задач 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();

    }

    }
}

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

1012 * Stefano *

Ответы [ 5 ]

6 голосов
/ 12 ноября 2009

Вы не утилизируете свой 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");
}
1 голос
/ 12 ноября 2009

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

0 голосов
/ 18 апреля 2013

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

0 голосов
/ 12 января 2012
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 голосов
/ 12 ноября 2009

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

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

...