C# 运行windows服务以查看服务运行时内存增长(泄漏)

C# 运行windows服务以查看服务运行时内存增长(泄漏),c#,windows,memory,service,memory-leaks,C#,Windows,Memory,Service,Memory Leaks,我已经检查了这里的所有帖子,但到目前为止还没有找到解决方案。 我确实设置了一个小服务,它应该只监视我的其他服务是否运行,如果不运行,则重新启动它并在应用程序事件日志中放置一条消息 这项服务本身工作得很好,没什么特别的:),但当我开始这项服务时,它使用了大约1.6MB的RAM,每10秒它就会增长60-70k,这对我来说是一个很大的挑战。 我试图处理并清除所有资源。尝试使用系统。计时器代替了实际的解决方案,但没有任何东西能像我所希望的那样工作,内存仍然在增长 调试或发布版本没有区别,我在.NET2上

我已经检查了这里的所有帖子,但到目前为止还没有找到解决方案。 我确实设置了一个小服务,它应该只监视我的其他服务是否运行,如果不运行,则重新启动它并在应用程序事件日志中放置一条消息

这项服务本身工作得很好,没什么特别的:),但当我开始这项服务时,它使用了大约1.6MB的RAM,每10秒它就会增长60-70k,这对我来说是一个很大的挑战。 我试图处理并清除所有资源。尝试使用系统。计时器代替了实际的解决方案,但没有任何东西能像我所希望的那样工作,内存仍然在增长

调试或发布版本没有区别,我在.NET2上使用它,不知道它是否会对您的3、3.5或4产生影响

有什么提示吗

using System;
using System.IO;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Timers;

namespace Watchguard
{
  class WindowsService : ServiceBase
  {

    Thread mWorker;
    AutoResetEvent mStop = new AutoResetEvent(false);

    /// <summary>
    /// Public Constructor for WindowsService.
    /// - Put all of your Initialization code here.
    /// </summary>
    public WindowsService()
    {
        this.ServiceName = "Informer Watchguard";
        this.EventLog.Source = "Informer Watchguard";
        this.EventLog.Log = "Application";

      // These Flags set whether or not to handle that specific
        //  type of event. Set to true if you need it, false otherwise.
        this.CanHandlePowerEvent = false;
        this.CanHandleSessionChangeEvent = false;
        this.CanPauseAndContinue = false;
        this.CanShutdown = false;
        this.CanStop = true;

        if (!EventLog.SourceExists("Informer Watchguard"))
          EventLog.CreateEventSource("Informer Watchguard", "Application");
    }

    /// <summary>
    /// The Main Thread: This is where your Service is Run.
    /// </summary>
    static void Main()
    {
        ServiceBase.Run(new WindowsService());
    }

    /// <summary>
    /// Dispose of objects that need it here.
    /// </summary>
    /// <param name="disposing">Whether or not disposing is going on.</param>
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
    }

    /// <summary>
    /// OnStart: Put startup code here
    ///  - Start threads, get inital data, etc.
    /// </summary>
    /// <param name="args"></param>
    protected override void OnStart(string[] args)
    {

      base.OnStart(args);

      MyLogEvent("Init");

      mWorker = new Thread(WatchServices);
      mWorker.Start();

    }

    /// <summary>
    /// OnStop: Put your stop code here
    /// - Stop threads, set final data, etc.
    /// </summary>
    protected override void OnStop()
    {

      mStop.Set();
      mWorker.Join();

      base.OnStop();

    }

    /// <summary>
    /// OnSessionChange(): To handle a change event from a Terminal Server session.
    ///   Useful if you need to determine when a user logs in remotely or logs off,
    ///   or when someone logs into the console.
    /// </summary>
    /// <param name="changeDescription"></param>
    protected override void OnSessionChange(SessionChangeDescription changeDescription)
    {
      base.OnSessionChange(changeDescription);
    }

    private void WatchServices()
    {

      string scName = "";

      ServiceController[] scServices;
      scServices = ServiceController.GetServices();

      for (; ; )
      {
        // Run this code once every 10 seconds or stop right away if the service is stopped
        if (mStop.WaitOne(10000)) return;
        // Do work...
        foreach (ServiceController scTemp in scServices)
        {

          scName = scTemp.ServiceName.ToString().ToLower();

          if (scName == "InformerWatchguard") scName = ""; // don't do it for yourself

          if (scName.Length > 8) scName = scName.Substring(0, 8);

          if (scName == "informer")
          {

            ServiceController sc = new ServiceController(scTemp.ServiceName.ToString());

            if (sc.Status == ServiceControllerStatus.Stopped)
            {

              sc.Start();
              MyLogEvent("Found service " + scTemp.ServiceName.ToString() + " which has status: " + sc.Status + "\nRestarting Service...");

            }

            sc.Dispose();
            sc = null;

          }
        }
      }

    }

    private static void MyLogEvent(String Message)
    {
      // Create an eEventLog instance and assign its source.
      EventLog myLog = new EventLog();
      myLog.Source = "Informer Watchguard";

      // Write an informational entry to the event log.
      myLog.WriteEntry(Message);
    }
  }
}
使用系统;
使用System.IO;
使用系统诊断;
使用System.ServiceProcess;
使用系统线程;
使用系统计时器;
命名空间Watchguard
{
类WindowsService:ServiceBase
{
螺纹加工工;
AutoResetEvent mStop=新的AutoResetEvent(假);
/// 
///WindowsService的公共构造函数。
///-将所有初始化代码放在此处。
/// 
公共服务
{
this.ServiceName=“Informer Watchguard”;
this.EventLog.Source=“Informer Watchguard”;
this.EventLog.Log=“应用程序”;
//这些标志设置是否处理该特定事件
//事件类型。如果需要,请将其设置为true,否则设置为false。
this.canhandlepowerprevent=false;
this.CanHandleSessionChangeEvent=false;
this.CanPauseAndContinue=false;
this.CanShutdown=false;
this.CanStop=true;
如果(!EventLog.SourceExists(“Informer Watchguard”))
CreateEventSource(“Informer Watchguard”、“应用程序”);
}
/// 
///主线程:这是运行服务的地方。
/// 
静态void Main()
{
运行(新的WindowsService());
}
/// 
///在此处处置需要它的对象。
/// 
///是否正在进行处置。
受保护的覆盖无效处置(布尔处置)
{
基地。处置(处置);
}
/// 
///OnStart:将启动代码放在这里
///-启动线程、获取初始数据等。
/// 
/// 
启动时受保护的覆盖无效(字符串[]args)
{
base.OnStart(args);
MyLogEvent(“初始”);
mWorker=新线程(WatchServices);
mWorker.Start();
}
/// 
///顶部:把你的停止代码放在这里
///-停止线程,设置最终数据等。
/// 
受保护的覆盖void OnStop()
{
mStop.Set();
mWorker.Join();
base.OnStop();
}
/// 
///OnSessionChange():处理终端服务器会话中的更改事件。
///如果您需要确定用户何时远程登录或何时注销,此功能非常有用,
///或者当有人登录控制台时。
/// 
/// 
受保护的覆盖无效OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
私人服务()
{
字符串scName=“”;
服务控制器[]服务;
scServices=ServiceController.GetServices();
对于(;;)
{
//每10秒运行一次此代码,如果服务停止,请立即停止
if(mStop.WaitOne(10000))返回;
//做工作。。。
foreach(scServices中的服务控制器scTemp)
{
scName=scTemp.ServiceName.ToString().ToLower();
如果(scName==“InformerWatchguard”)scName=“;//不要为自己这么做
如果(scName.Length>8)scName=scName.Substring(0,8);
如果(scName==“告密者”)
{
ServiceController sc=新的ServiceController(scTemp.ServiceName.ToString());
如果(sc.Status==ServiceControllerStatus.Stopped)
{
sc.Start();
MyRogeEvent(“找到的服务”+scTemp.ServiceName.ToString()+”,其状态为:“+sc.status+”\n重新启动服务…”);
}
sc.Dispose();
sc=null;
}
}
}
}
私有静态void MyLogEvent(字符串消息)
{
//创建eEventLog实例并分配其源。
EventLog myLog=新的EventLog();
myLog.Source=“Informer Watchguard”;
//将信息条目写入事件日志。
myLog.WriteEntry(消息);
}
}
}

至少,您需要在日志代码中执行此操作,因为
EventLog
需要是
Dispose()
d。似乎每次调用时都可以重用此资源,而不是
new
-ed。您也可以在主循环中使用<代码> > <代码>服务管理器< /Cord>对象,以使代码更加异常安全。

private static void MyLogEvent(String Message)
{
  // Create an eEventLog instance and assign its source.
  using (EventLog myLog = new EventLog())
 {
   myLog.Source = "Informer Watchguard";

   // Write an informational entry to the event log.
   myLog.WriteEntry(Message);
 }
}

您的代码可能会在循环中抛出异常,但这些异常不会被捕获。因此,按如下方式更改代码以捕获异常:

if (scName == "informer")
{
    try {
        using(ServiceController sc = new ServiceController(scTemp.ServiceName.ToString())) {
            if (sc.Status == ServiceControllerStatus.Stopped)
            {
                sc.Start();
                MyLogEvent("Found service " + scTemp.ServiceName.ToString() + " which has status: " + sc.Status + "\nRestarting Service...");
            }
        }
    } catch {
        // Write debug log here
    }
}

您可以在调查后删除外部try/catch,使用语句保留
,以确保即使内部抛出异常也调用了Dispose。

这应该被移动到循环中,因为您不希望在服务生命周期中保留对旧服务句柄的引用:

ServiceController[] scServices = ServiceController.GetServices();
您还需要处理对
EventLog
ServiceController
实例的引用。正如Artem所指出的,要注意阻止您这样做的异常

由于内存每10秒增加一次,所以它必须是您循环中的某个内容

如果无论是否写入事件日志,内存都会增加,那么这不是主要问题

使用过的记忆会下降吗?垃圾收集员过一会儿就开始工作了吗?您可以在回去睡觉之前通过执行一个
GC.Collect()
来测试GC的效果(尽管我会小心地在生产中使用它)