我在使用C#编写的Windows服务中的内存管理方面遇到了一些问题(框架3.5,visual studio 2008)。
服务运行正常,使用Timer和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();
}
}
}
任何帮助将不胜感激!
斯特凡诺
答案 0 :(得分: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");
}
答案 1 :(得分:1)
此外,.NET的垃圾收集在遇到某些最佳参数时运行。如果系统内存不足,可能会认为运行GC.Collect太昂贵了,因此你的非引用但仍然在内存中的对象会继续保持这种状态。
答案 2 :(得分:0)
我会假设您的文件不断增长,因为您要添加新行 到最后,因此,节水器消耗更多的内存。
我宁愿在programm启动时创建一个流编写器 而不是在回调时这样做。但是你会锁定一个文件 通过您的服务。
答案 3 :(得分: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);
}
}
答案 4 :(得分:0)
最好使用File.AppendAllText(path, content);
,它将处理所有内存泄漏。